def __init__(self, config, environ, logdispatcher, statechglogger): RuleKVEditor.__init__(self, config, environ, logdispatcher, statechglogger) self.rulenumber = 131 self.rulename = 'ShowBluetoothIcon' self.formatDetailedResults("initialize") self.mandatory = False self.sethelptext() self.rootrequired = False self.guidance = [] self.statechglogger = statechglogger self.applicable = { 'type': 'white', 'os': { 'Mac OS X': ['10.15', 'r', '10.15.10'] } } self.ch = CommandHelper(self.logdispatch) self.systemuiserver = "" self.bluetoothmenu = "" if self.environ.geteuid() != 0: user = pwd.getpwuid(os.getuid())[0] self.systemuiserver = "/Users/" + user + "/Library/Preferences/com.apple.systemuiserver" self.bluetoothmenu = "\"/System/Library/CoreServices/Menu Extras/Bluetooth.menu\"" self.addKVEditor( "ShowBluetoothIcon", "defaults", self.systemuiserver, "", { "menuExtras": [self.bluetoothmenu, "-array-add " + self.bluetoothmenu] }, "present", "", "Show Bluetooth Icon in the Menu Bar.", None, False, {})
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 localize(self): """ set paths based on what versions of which utilities exist on the system :return: void """ self.gsettings = "/usr/bin/gsettings" self.gconf = "/usr/bin/gconftool-2" self.dconf = "/usr/bin/dconf" self.getcmd = "" self.setcmd = "" self.updatecmd = "" packages = ["gnome", "gdm", "gdm3", "gnome3"] self.lockfile = "/etc/dconf/db/local.d/locks/stonix-thumbnailers" self.lockthumbnails = {"/org/gnome/desktop/thumbnailers/disable-all":""} if os.path.exists(self.gsettings): self.getcmd = self.gsettings + " get org.gnome.desktop.thumbnailers disable-all" self.setcmd = self.gsettings + " set org.gnome.desktop.thummailerss disable-all true" elif os.path.exists(self.gconf): self.getcmd = self.gconf + " --get /schemas/org/gnome/desktop/thumbnailers/disable_all" self.setcmd = self.gconf + " --type bool --set /schemass/org/gnome/desktop/thumbnailers/disable_all true" if os.path.exists(self.dconf): self.updatecmd = self.dconf + " update" self.ch = CommandHelper(self.logger) self.ph = Pkghelper(self.logger, self.environ) self.gnome_installed = False if self.environ.getosname() != "Mac OS": if [self.ph.check(p) for p in packages]: self.gnome_installed = True
def __init__(self, config, enviro, logger, statechglogger): Rule.__init__(self, config, enviro, logger, statechglogger) self.logger = logger self.rulenumber = 89 self.rulename = "DisablePrelinking" self.sethelptext() self.formatDetailedResults("initialize") self.mandatory = True self.applicable = {'type': 'white', 'family': ['linux']} # Configuration item instantiation datatype = "bool" key = "DISABLEPRELINKING" instructions = "To disable this rule, set the value of " + \ "DISABLEPRELINKING to false." default = True self.ci = self.initCi(datatype, key, instructions, default) self.guidance = ["CCE-RHEL7-CCE-TBA 2.1.3.1.2"] self.iditerator = 0 self.ch = CommandHelper(self.logger) if re.search("debian|ubuntu", self.environ.getostype().lower()): self.isDebian = True else: self.isDebian = False
def __init__(self, config, environ, logger, statechglogger): """ Constructor """ Rule.__init__(self, config, environ, logger, statechglogger) self.logger = logger self.rulenumber = 9 self.rulename = 'SystemAccounting' self.formatDetailedResults("initialize") self.mandatory = False self.rootrequired = True self.sethelptext() self.guidance = ['CIS 2.4', 'cce-3992-5'] self.applicable = { 'type': 'white', 'family': 'linux', 'os': { 'Mac OS X': ['10.15', 'r', '10.15.10'] } } # set up configuration item for this rule datatype = 'bool' key = 'SYSTEMACCOUNTING' instructions = "This is an optional rule and is disabled by default, due to the significant load it can place on the system when enabled. To enable system accounting, set the value of SYSTEMACCOUNTING to True." default = False self.ci = self.initCi(datatype, key, instructions, default) self.ostype = self.environ.getostype() self.ph = Pkghelper(self.logger, self.environ) self.ch = CommandHelper(self.logger) self._set_paths()
def __init__(self, config, enviro, logger, statechglogger): Rule.__init__(self, config, enviro, logger, statechglogger) self.logger = logger self.rulenumber = 132 self.rulename = "DisableUncommonProtocols" self.formatDetailedResults("initialize") self.mandatory = False self.applicable = {'type': 'white', "family": ["linux"]} # Configuration item instantiation datatype = "bool" key = "DISABLEUNCOMMONPROTOCOLS" instructions = "To disable this rule, set the value of " + \ "DISABLEUNCOMMONPROTOCOLS to false." default = True self.ci = self.initCi(datatype, key, instructions, default) datatype = "list" key = "PROTOCOLS" instructions = "List all network protocols to disable" default = ["dccp", "sctp", "rds", "tipc"] self.ci2 = self.initCi(datatype, key, instructions, default) self.guidance = [ "NSA 2.5.7", "CIS 4.6", "CCE-26448-1", "CCE-26410-1", "CCE-26239-4", "CCE-26696-5", "CCE-26828-4", "CCE-27106-4" ] self.iditerator = 0 self.ch = CommandHelper(self.logger) self.sethelptext()
def report(self): """report on the status of the system's compliance with disallowing system accounts to log in :return: self.compliant - boolean; True if compliant, False if not """ self.detailedresults = "" self.compliant = True acceptable_nologin_shells = ["/sbin/nologin", "/dev/null", "", "/usr/bin/false"] self.ch = CommandHelper(self.logger) self.corrections_needed = [] try: system_login_shells = self.getsysloginshells() for acc in system_login_shells: if system_login_shells[acc] not in acceptable_nologin_shells: self.compliant = False self.corrections_needed.append(acc) if self.corrections_needed: self.detailedresults += "\nThe following system accounts can log in:\n" + "\n".join(self.corrections_needed) except (KeyboardInterrupt, SystemExit): raise except Exception: self.compliant = False self.detailedresults = traceback.format_exc() 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 reportMac(self): self.ifaces = [] compliant = True self.cmdhelper = CommandHelper(self.logger) cmd = ["/usr/sbin/networksetup", "-listallnetworkservices"] if not self.cmdhelper.executeCommand(cmd): self.detailedresults += "Unable to run " + \ "networksetup -listallnetworkservices command\n" return False output = self.cmdhelper.getOutput() for item in output: item = item.strip() cmd = ["/usr/sbin/networksetup", "-getinfo", item] if not self.cmdhelper.executeCommand(cmd): self.detailedresults += "Unable to run " + \ "networksetup -getinfo command\n" return False output2 = self.cmdhelper.getOutput() for item2 in output2: if re.search("^IPv6:", item2): check = item2.split(":") if check[1].strip() != "Off": self.detailedresults += "IPV6 is not turned off " + \ "for " + item + " interface\n" self.ifaces.append(item) compliant = False return compliant
def report(self): try: self.detailedresults = "" compliant = True cmd = ["/bin/launchctl", "list"] self.ch = CommandHelper(self.logger) if self.ch.executeCommand(cmd): output = self.ch.getOutput() for line in output: if re.search("com\.apple\.ftpd", line): self.detailedresults += "FTP is running and it shouldn't\n" compliant = False break else: self.detailedresults += "Unable to list running services\n" compliant = False self.compliant = compliant except (KeyboardInterrupt, SystemExit): # User initiated exit raise except Exception: self.rulesuccess = False 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 __init__(self, config, environ, logger, statechglogger): '''Constructor''' Rule.__init__(self, config, environ, logger, statechglogger) self.logger = logger self.rulenumber = 160 self.rulename = "DisableRoot" self.formatDetailedResults("initialize") self.mandatory = True self.applicable = { 'type': 'white', 'os': { 'Mac OS X': ['10.15', 'r', '10.15.10'] } } # configuration item instantiation datatype = 'bool' key = 'DISABLEROOT' instructions = "To disable this rule set the value of DISABLEROOT " + \ "to False." default = True self.ci = self.initCi(datatype, key, instructions, default) self.cmdhelper = CommandHelper(self.logger) self.guidance = ["NSA 1.3.14"] self.sethelptext()
def report(self): try: compliant = False self.detailedresults = "" self.ch = CommandHelper(self.logger) cmd = ["/usr/bin/profiles", "-P"] if not self.ch.executeCommand(cmd): compliant = False self.detailedresults += "Unable to run profiles command\n" else: output = self.ch.getOutput() if output: for line in output: if search("^There are no configuration profiles installed", line.strip()): compliant = False self.detailedresults += "There are no configuration profiles installed\n" break elif search("mil\.disa\.STIG\.Restrictions\.alacarte$", line.strip()): compliant = True break self.compliant = compliant except (KeyboardInterrupt, SystemExit): # User initiated exit raise except Exception: self.rulesuccess = False self.detailedresults += "\n" + traceback.format_exc() self.logdispatch.log(LogPriority.ERROR, self.detailedresults) self.formatDetailedResults("report", self.compliant, self.detailedresults) self.logdispatch.log(LogPriority.INFO, self.detailedresults) return self.compliant
def __init__(self, config, environ, logger, statechglogger): """ private method to initialize the module :param config: :param environ: :param logger: :param statechglogger: """ Rule.__init__(self, config, environ, logger, statechglogger) self.config = config self.environ = environ self.logger = logger self.commandhelper = CommandHelper(self.logger) self.statechglogger = statechglogger self.rulenumber = 58 self.rulename = 'CheckDupIDs' self.formatDetailedResults("initialize") self.mandatory = True self.rootrequired = True self.guidance = ['CCE-RHEL7-CCE-TBD 2.4.1.2.3'] self.sethelptext() self.applicable = { 'type': 'white', 'family': ['linux', 'solaris', 'freebsd'], 'os': { 'Mac OS X': ['10.15', 'r', '10.15.10'] } } self.issuelist = [] self.auditonly = True
def init_objs(self): """ """ self.ph = Pkghelper(self.logger, self.environ) self.ch = CommandHelper(self.logger)
def __init__(self, logger): self.logger = logger self.detailedresults = "" self.ch = CommandHelper(self.logger) self.install = "emerge " self.remove = self.install + " --unmerge " self.search = self.install + " --search "
def __init__(self, config, enviro, logger, statechglogger): Rule.__init__(self, config, enviro, logger, statechglogger) self.logger = logger self.rulenumber = 124 self.rulename = "SecureIPV6" self.formatDetailedResults("initialize") self.mandatory = True self.sethelptext() datatype = "bool" key = "SECUREIPV6" instructions = '''To disable this rule set the value of SECUREIPV6 to \ False.''' default = True self.ci = self.initCi(datatype, key, instructions, default) self.guidance = ["NSA 2.5.3.2", "CCE 4269-7", "CCE 4291-1", "CCE 4313-3", "CCE 4198-8", "CCE 3842-2", "CCE 4221-8", "CCE 4137-6", "CCE 4159-0", "CCE 3895-0", "CCE 4287-9", "CCE 4058-4", "CCE 4128-5"] self.applicable = {'type': 'white', 'family': ['linux'], 'os': {'Mac OS X': ['10.15', 'r', '10.15.10']}} self.iditerator = 0 # self.editor1: sysctl file editor # self.editor2: network file editor self.editor1, self.editor2 = "", "" self.ch = CommandHelper(self.logger)
def __init__(self, config, environ, logger, statechglogger): ''' Constructor ''' Rule.__init__(self, config, environ, logger, statechglogger) self.rulenumber = 208 self.rulename = 'DisableWebSharing' self.formatDetailedResults("initialize") self.mandatory = True self.compliant = False self.rootrequired = True self.guidance = ['CIS 1.4.14.6'] self.applicable = { 'type': 'white', 'os': { 'Mac OS X': ['10.15', 'r', '10.15.10'] } } self.logger = logger # set up CIs datatype = 'bool' key = 'DISABLEWEBSHARING' instructions = 'To prevent web sharing from being disabled, set the value of DisableWebSharing to False.' default = True self.disableWebSharing = self.initCi(datatype, key, instructions, default) # set up class var's self.maclongname = '/System/Library/LaunchDaemons/org.apache.httpd.plist' self.macshortname = 'org.apache.httpd' self.svchelper = ServiceHelper(self.environ, self.logger) self.cmhelper = CommandHelper(self.logger) self.sethelptext()
def __init__(self, logger): self.logger = logger self.detailedresults = "" self.ch = CommandHelper(self.logger) self.install = "/usr/bin/yum install -y " self.remove = "/usr/bin/yum remove -y " self.search = "/usr/bin/yum search " self.rpm = "/bin/rpm -q "
def report(self): """check status of private ssh keys (whether they are encrypted with passwords or not) :returns: self.compliant - boolean; True if compliant, False if not compliant """ searchterm = "Proc-Type:" self.searchdirs = [] keylist = [] self.keydict = {} self.compliant = True self.detailedresults = "" self.ch = CommandHelper(self.logger) try: self.logger.log(LogPriority.DEBUG, "Getting list of user home directories...") self.searchdirs = self.get_search_dirs() self.logger.log(LogPriority.DEBUG, "Getting list of ssh keys...") keylist = self.get_key_list(self.searchdirs) if keylist: self.logger.log(LogPriority.DEBUG, "Searching list of ssh keys...") for key in keylist: self.keydict[key] = False f = open(key, "r") contentlines = f.readlines() f.close() for line in contentlines: if re.search(searchterm, line): self.keydict[key] = True for key in self.keydict: if not self.keydict[key]: self.compliant = False self.detailedresults += "\nThe SSH key: " + str(key) + " was made without a password!" if getOctalPerms(key) != 600: self.compliant = False self.detailedresults += "\nThe SSH key: " + str(key) + " has incorrect permissions" if self.compliant: self.detailedresults += "\nAll SSH keys on this system are encrypted" else: self.detailedresults += "\nNo SSH keys were found on this system." if not self.compliant: self.detailedresults += "\n\nThis rule's fix only changes permissions on insecure keys. We cannot fix keys which were made without a password." except (KeyboardInterrupt, SystemExit): raise except Exception: self.compliant = False self.detailedresults = str(traceback.format_exc()) self.logger.log(LogPriority.ERROR, self.detailedresults) self.formatDetailedResults("report", self.compliant, self.detailedresults) return self.compliant
def initobjs(self): '''initialize class objects @author: Breen Malmberg ''' self.ch = CommandHelper(self.logger)
def __init__(self, logger): self.logger = logger self.detailedresults = "" self.ch = CommandHelper(self.logger) self.install = "/usr/bin/zypper --non-interactive install " self.remove = "/usr/bin/zypper --non-interactive remove " self.searchi = "/usr/bin/zypper --non-interactive search --match-exact -i " self.searchu = "/usr/bin/zypper --non-interactive search --match-exact -u " self.rpm = "/bin/rpm -q "
def initobjs(self): '''initialize helper objects @author: Breen Malmberg ''' self.ch = CommandHelper(self.logger) self.pkg = Pkghelper(self.logger, self.environ)
def send_color(row): color_command = CommandHelper() _, hex_color = askcolor() # Rückgabewert ist ein Tupel mit ((R,G,B), #Hex) if hex_color: hex_color = hex_color.replace("#", "") color_int = int(hex_color, 16) if devices[row]: devices[row].execute_command(color_command.set_color(color_int))
def __init__(self, config, environ, logger, statechglogger): """ private method to initialize the module :param config: configuration object instance :param environ: environment object instance :param logger: logdispatcher object instance :param statechglogger: statechglogger object instance """ Rule.__init__(self, config, environ, logger, statechglogger) self.rulenumber = 18 self.rulename = 'BootSecurity' self.formatDetailedResults("initialize") self.mandatory = True self.sethelptext() self.rootrequired = True self.guidance = [] self.applicable = { 'type': 'white', 'family': ['linux'], 'os': { 'Mac OS X': ['10.15', 'r', '10.15.10'] } } self.servicehelper = ServiceHelper(environ, logger) self.ch = CommandHelper(self.logdispatch) if os.path.exists('/bin/systemctl'): self.type = 'systemd' elif os.path.exists('/sbin/launchd'): self.type = 'mac' else: self.type = 'rclocal' self.rclocalpath = '/etc/rc.local' if os.path.islink(self.rclocalpath): paths = ['/etc/rc.d/rc.local', '/etc/init.d/rc.local'] for rcpath in paths: if os.path.isfile(rcpath): self.rclocalpath = rcpath self.logdispatch.log(LogPriority.DEBUG, 'Using rc.local file ' + self.rclocalpath) datatype = 'bool' key = 'BOOTSECURITY' instructions = """To disable this rule set the value of BOOTSECURITY to False.""" default = True self.bootci = self.initCi(datatype, key, instructions, default) datatype2 = 'bool' key2 = 'ENABLEFIPS' instructions2 = """!WARNING! DO NOT ENABLE THIS OPTION IF YOUR SYSTEM IS ARLEADY FDE ENCRYPTED! To enable full fips compliance on this system, at boot, set the value of ENABLEFIPS to True.""" default2 = False self.fips_ci = self.initCi(datatype2, key2, instructions2, default2) self.set_paths()
def initObjs(self): '''initialize any objects to be used by this class :returns: void @author: Breen Malmberg ''' self.cmdhelper = CommandHelper(self.logger)
def __init__(self, logger): '''Remember, for solaris sparc systems, the package names will typically begin with SUNW''' self.logger = logger self.detailedresults = "" self.sparc = "(.)*sparc(.)*" self.ch = CommandHelper(self.logger) self.install = "/usr/sbin/pkgadd -n -i " self.remove = "/usr/sbin/pkgrm -n " self.info = "/usr/bin/pkginfo "
def initobjs(self): '''init objects used by this class @author: Breen Malmberg ''' self.ch = CommandHelper(self.logger) self.fixed = False
def report(self): """ The report method examines the current configuration and determines whether or not it is correct. If the config is correct then the self.compliant, self.detailedresults and self.currstate properties are updated to reflect the system status. self.rulesuccess will be updated if the rule does not succeed. :return: self.compliant :rtype: bool """ # defaults self.detailedresults = "" self.ch = CommandHelper(self.logger) # set up list of files which need to be checked and configured self.rootfiledict = { "/root/.bash_profile": False, "/root/.bashrc": False, "/root/.cshrc": False, "/root/.tcshrc": False } self.userfiledict = { "/etc/profile": False, "/etc/csh.login": False, "/etc/csh.cshrc": False, "/etc/bashrc": False, "/etc/zshrc": False, "/etc/login.conf": False, "/etc/bash.bashrc": False, "/etc/login.defs": False } try: # decide which report method to run based on osfamily if self.environ.getosfamily() == 'darwin': self.compliant = self.reportmac() else: self.compliant = self.reportnix() except (KeyboardInterrupt, SystemExit): raise except Exception as err: self.compliant = 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 __init__(self, config, environ, logdispatcher, statechglogger): RuleKVEditor.__init__(self, config, environ, logdispatcher, statechglogger) self.rulenumber = 122 self.rulename = 'ConfigureNetworks' self.formatDetailedResults("initialize") self.mandatory = True self.sethelptext() self.rootrequired = True self.guidance = [] self.iditerator = 0 self.statechglogger = statechglogger self.applicable = { 'type': 'white', 'os': { 'Mac OS X': ['10.15', 'r', '10.15.10'] } } ## this section added to prevent code, which relies on constants in localize.py, # from running if those constants are not defined or are set to 'None' # if DNS == None: # self.logdispatch.log(LogPriority.DEBUG, "Please ensure that the following constants, in localize.py, are correctly defined and are not None: DNS, PROXY, PROXYCONFIGURATIONFILE, PROXYDOMAIN. ConfigureNetworks will not function without these!") # exit # if PROXY == None: # self.logdispatch.log(LogPriority.DEBUG, "Please ensure that the following constants, in localize.py, are correctly defined and are not None: DNS, PROXY, PROXYCONFIGURATIONFILE, PROXYDOMAIN. ConfigureNetworks will not function without these!") # exit # if PROXYCONFIGURATIONFILE == None: # self.logdispatch.log(LogPriority.DEBUG, "Please ensure that the following constants, in localize.py, are correctly defined and are not None: DNS, PROXY, PROXYCONFIGURATIONFILE, PROXYDOMAIN. ConfigureNetworks will not function without these!") # exit # if PROXYDOMAIN == None: # self.logdispatch.log(LogPriority.DEBUG, "Please ensure that the following constants, in localize.py, are correctly defined and are not None: DNS, PROXY, PROXYCONFIGURATIONFILE, PROXYDOMAIN. ConfigureNetworks will not function without these!") # exit # this section added to prevent code, which relies on constants in localize.py, ## from running if those constants are not defined or are set to 'None' self.nsobject = None self.nsobject = networksetup(self.logdispatch) if self.nsobject != None: self.ch = CommandHelper(self.logdispatch) self.sh = ServiceHelper(self.environ, self.logdispatch) self.addKVEditor("DisableBluetoothUserInterface", "defaults", "/Library/Preferences/com.apple.Bluetooth", "", {"ControllerPowerState": ["0", "-int 0"]}, "present", "", "Disable Bluetooth User Interface.", None, False, {}) self.addKVEditor("DisableBluetoothInternetSharing", "defaults", "/Library/Preferences/com.apple.Bluetooth", "", {"PANServices": ["0", "-int 0"]}, "present", "", "Disable Bluetooth Internet Sharing.", None, False, {})
def __init__(self, config, environ, logdispatcher, statechglogger): RuleKVEditor.__init__(self, config, environ, logdispatcher, statechglogger) self.rulenumber = 14 self.rulename = 'ConfigureFirewall' self.formatDetailedResults("initialize") self.mandatory = True self.sethelptext() self.rootrequired = True self.guidance = [] self.applicable = { 'type': 'white', 'os': { 'Mac OS X': ['10.12', 'r', '10.15.10'] } } self.ch = CommandHelper(self.logdispatch) self.sh = ServiceHelper(self.environ, self.logdispatch) self.fwcmd = "/usr/libexec/ApplicationFirewall/socketfilterfw" self.list = self.fwcmd + " --listapps" self.add = self.fwcmd + " --add " self.rmv = self.fwcmd + " --remove " self.iditerator = 0 datatype = 'bool' key = 'CONFIGUREFIREWALL' instructions = "To disable this rule set CONFIGUREFIREWALL to False\n" default = True self.ci = self.initCi(datatype, key, instructions, default) self.addKVEditor("FirewallOn", "defaults", "/Library/Preferences/com.apple.alf", "", {"globalstate": ["1", "-int 1"]}, "present", "", "Turn On Firewall. When enabled.", None, False, {"globalstate": ["0", "-int 0"]}) self.addKVEditor("FirewallLoginEnabled", "defaults", "/Library/Preferences/com.apple.alf", "", {"loggingenabled": ["1", "-int 1"]}, "present", "", "Login Enabled. When enabled.", None, False, {"loggingenabled": ["0", "-int 0"]}) self.addKVEditor("FirewallStealthDisabled", "defaults", "/Library/Preferences/com.apple.alf", "", {"stealthenabled": ["0", "-int 0"]}, "present", "", "Stealth Disabled. When enabled.", None, False, {"stealthenabled": ["1", "-int 1"]}) # self.currallowed = [] '''Any values inside stonix.conf overrule the values inserted in the text field unless changes are saved to stonix.conf''' '''There are no currently allowed apps for the fw''' datatype = 'list' key = 'ALLOWEDAPPS' instructions = "Comma separated list of Applications allowed by the firewall.\n" + \ "Most applications end with .app and must contain the full path to the application.\n" default = [] self.appci = self.initCi(datatype, key, instructions, default, ",")
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 __init__(self, logger): self.logger = logger self.detailedresults = "" self.ch = CommandHelper(self.logger) self.install = "sudo DEBIAN_FRONTEND=noninteractive /usr/bin/apt-get \ -y install " self.remove = "/usr/bin/apt-get -y remove "
def __init__(self,logger): self.logger = logger self.detailedresults = "" self.ch = CommandHelper(self.logger) self.install = "/usr/bin/yum install -y " self.remove = "/usr/bin/yum remove -y " self.search = "/usr/bin/yum search " self.rpm = "/bin/rpm -q "
def initobjs(self): """ initialize class objects @return: """ self.ch = CommandHelper(self.logger)
def __init__(self, logger): self.logger = logger self.detailedresults = "" self.ch = CommandHelper(self.logger) self.install = "/usr/bin/zypper --non-interactive install " self.remove = "/usr/bin/zypper --non-interactive remove " self.searchi = "/usr/bin/zypper --non-interactive search --match-exact -i " self.searchu = "/usr/bin/zypper --non-interactive search --match-exact -u "
class Solaris(object): def __init__(self,logger): '''Remember, for solaris sparc systems, the package names will typically begin with SUNW''' self.logger = logger self.detailedresults = "" self.sparc = "(.)*sparc(.)*" self.ch = CommandHelper(self.logger) self.install = "/usr/sbin/pkgadd -n -i " self.remove = "/usr/sbin/pkgrm -n " self.info = "/usr/bin/pkginfo " ############################################################################### def installpackage(self, package): ''' Install a package. Return a bool indicating success or failure. @param string package : Name of the package to be installed, must be recognizable to the underlying package manager. @return bool : @author''' try: # retval = call(self.install + package,stdout=None,shell=True) # if retval == 0: self.ch.executeCommand(self.install + package) if self.ch.getReturnCode() == 0: self.detailedresults = package + " pkg installed successfully" self.logger.log(LogPriority.INFO, ["Solaris.install",self.detailedresults]) return True else: self.detailedresults = package + " pkg not able to install." self.detailedresults += "This package may not be available, \ may be mispelled, or may depend on other packages in which non\ interactive mode can't be used" self.logger.log(LogPriority.INFO, ["Solaris.install",self.detailedresults]) return False except(KeyboardInterrupt,SystemExit): raise except Exception, err: #print err self.detailedresults = traceback.format_exc() self.logger.log(LogPriority.INFO, ['Solaris.install',self.detailedresults])
def __init__(self, environment, logdispatcher): """ Constructor """ super(SHsystemctl, self).__init__(environment, logdispatcher) self.environment = environment self.logdispatcher = logdispatcher self.ch = CommandHelper(self.logdispatcher) self.localize()
def __init__(self,logger): '''Remember, for solaris sparc systems, the package names will typically begin with SUNW''' self.logger = logger self.detailedresults = "" self.sparc = "(.)*sparc(.)*" self.ch = CommandHelper(self.logger) self.install = "/usr/sbin/pkgadd -n -i " self.remove = "/usr/sbin/pkgrm -n " self.info = "/usr/bin/pkginfo "
def __init__(self, logger): self.logger = logger self.ch = CommandHelper(self.logger) self.zyploc = "/usr/bin/zypper" self.install = self.zyploc + " --non-interactive --quiet install " self.remove = self.zyploc + " --non-interactive remove " self.searchi = self.zyploc + " --non-interactive search --match-exact -i " self.searchu = self.zyploc + " --non-interactive search --match-exact -u " self.updates = self.zyploc + " lu " self.upzypp = self.zyploc + " up " self.rpm = "/usr/bin/rpm -q " self.pkgtype = "zypper"
def __init__(self, logger): self.logger = logger self.ch = CommandHelper(self.logger) self.aptgetloc = "/usr/bin/apt-get" self.aptcacheloc = "/usr/bin/apt-cache" self.dpkgloc = "/usr/bin/dpkg" self.aptinstall = "DEBIAN_FRONTEND=noninteractive " + self.aptgetloc + " -y --assume-yes install " self.aptremove = "DEBIAN_FRONTEND=noninteractive " + self.aptgetloc + " -y remove " self.dpkgsearch = self.dpkgloc + " -S " self.dpkgchkinstalled = self.dpkgloc + " -l " self.aptchkupdates = self.aptgetloc + " -u upgrade --assume-no " self.aptupgrade = self.aptgetloc + " -u upgrade --assume-yes " self.aptchkavail = self.aptcacheloc + " policy "
def __init__(self, logger): ''' initialize lanlMacInfo @author: ekkehard ''' self.logdispatch = logger # Make sure we have the full path for all commands self.ch = CommandHelper(logger) self.LANLAssetTagNVRAM = "" self.LANLAssetTagFilesystem = "" self.macAddressDictionary = {} self.dictionary = {} self.accuracyDictionary = {} self.dictionaryItem = None self.keys = None self.key = None self.keyIndexNumber = 0 self.keysNumberOf = 0 self.entries = -1 self.computerName = "" self.computerNameDiskUtility = "" self.hostName = "" self.hostNameDiskUtility = "" self.localHostname = "" self.localHostnameDiskUtility = "" self.endUsername = "" self.assetTag = "" # Make sure we have the full path for all commands self.ns = "/usr/sbin/networksetup" self.scutil = "/usr/sbin/scutil" self.jamf = "/usr/sbin/jamf" self.nvram = "/usr/sbin/nvram" self.ldap = "/usr/bin/ldapsearch" self.lanl_property_file = "/Library/Preferences/lanl_property_number.txt" # Initialize accuracy modules self.updateAssetTagAccuracy(True, 0, "", True) self.updateEndUserNameAccuracy(True, 0, "", True) self.updateComputerNameAccuracy(True, 0, "", True) # reset messages and initialize everyting self.messageReset() self.initializeLanlAssetTagNVRAM() self.initializeLanlAssetTagFilesystem() self.initializeDiskUtilityInfo() self.populateFromMac() self.determinAccuracy()
class AptGet(object): '''Linux specific package manager for distributions that use the apt-get command to install packages. :version: :author:Derek T Walker 08-06-2012''' def __init__(self, logger): self.logger = logger self.detailedresults = "" self.ch = CommandHelper(self.logger) self.install = "sudo DEBIAN_FRONTEND=noninteractive /usr/bin/apt-get \ -y install " self.remove = "/usr/bin/apt-get -y remove " ############################################################################### def installpackage(self, package): '''Install a package. Return a bool indicating success or failure. @param string package : Name of the package to be installed, must be recognizable to the underlying package manager. @return bool : @author dwalker''' try: self.ch.executeCommand(self.install + package) if self.ch.getReturnCode() == 0: self.detailedresults = package + " pkg installed successfully" self.logger.log(LogPriority.INFO, ["AptGet.install",self.detailedresults]) return True else: #try to install for a second time self.ch.executeCommand(self.install + package) if self.ch.getReturnCode() == 0: self.detailedresults = package + " pkg installed successfully" self.logger.log(LogPriority.INFO, ["AptGet.install",self.detailedresults]) return True else: self.detailedresults = package + " pkg not able to install" self.logger.log(LogPriority.INFO, ["AptGet.install",self.detailedresults]) return False except(KeyboardInterrupt,SystemExit): raise except Exception, err: print err self.detailedresults = traceback.format_exc() self.logger.log(LogPriority.INFO, ["AptGet.install",self.detailedresults]) raise(self.detailedresults)
def commit(self): ''' @summary: Method that performs the install command to install the appropriate profile for the calling rule. @author: dwalker @return: bool - True or False ''' self.ch = CommandHelper(self.logger) if self.installcmd: if not self.ch.executeCommand(self.installcmd): return False elif self.ch.getReturnCode() != 0: return False else: return True else: return False return True
def validateProfiles(self): ''' @since: 3/10/2016 @author: dwalker @var self.data: A dictionary in the form of {k: {v: ["numberValue", "datatype", "acceptableDeviation"(optional)], v: ["", "", ""], v: ["", "", ""], . . .}} @var: k: The profile sub-identifier e.g. com.apple.mobiledevice.passwordpolicy @var v: The profile data key-value pairs in a dictionary e.g. allowSimple that will appear in the output of the system_profiler command within the first opening brace after the profile sub-identifier. v also contains an associated list containing: [a,b,c] a) the value on the other side of the = sign b) whether that value is an integer(int) or a boolean(bool) c) (optional) whether the value present after the = sign(a), if an int, can be lower(less) or higher(more) in order to detect and represent stringency (see self.data description above). @return: Value returned from validate method in factory sub-class @rtype: bool ''' cmd = ["/usr/sbin/system_profiler", "SPConfigurationProfileDataType"] self.ch = CommandHelper(self.logger) if self.ch.executeCommand(cmd): self.output = self.ch.getOutput() retval = True if self.output: for k, v in self.data.iteritems(): retval = self.editor.validate(self.output, k, v) if not retval: return False else: debug = "There are no profiles installed" self.logger.log(LogPriority.DEBUG, debug) return False return True
def __init__(self, logger): self.environ = Environment() self.logger = logger self.ch = CommandHelper(self.logger) self.yumloc = "/usr/bin/yum" self.install = self.yumloc + " install -y " self.remove = self.yumloc + " remove -y " self.search = self.yumloc + " list " self.checkupdates = self.search + "updates " self.listavail = self.search + "available " self.listinstalled = self.search + "installed " self.updatepkg = self.yumloc + " update -y --obsoletes " myos = self.environ.getostype().lower() if re.search("red hat.*?release 6", myos) or \ re.search("^centos$", myos.strip()): self.rpmloc = "/bin/rpm" else: self.rpmloc = "/usr/bin/rpm" self.provides = self.rpmloc + " -qf " self.query = self.rpmloc + " -qa "
class KVAProfiles(): def __init__(self, logger, path): self.logger = logger self.path = path self.undocmd = "" self.installcmd = "" def validate(self, output, key, val): ''' @summary: Method checks if either profile is installed and/or contents of profile is up to par with our security standards @author: dwalker @param output: The output from system_profiler SPConfigurationProfileDataType command @param key: The profile identifier we're looking for in the output. Usually takes the form of com.apple.example @param val: A dictionary which could contain other lists, dicts, and/or tuples nested within. Example: {"allowsimple": ["1", "bool"], "forcePIN": ["1", "bool"], ...} @return: bool - True or False ''' '''When passed through, key should be the identifier to be found such as com.apple.DiscRecording and val should be the rest of the dictionary.''' retval = True '''In some cases val will be blank in which case we're just looking for the presence of the profile or more specifically the identifier (key)''' if not val: for line in output: if re.search("^" + key, line.strip()): return True '''We never found the profile, return False''' debug = "The profile sub-identifier:" + key + " was not found\n" self.logger.log(LogPriority.DEBUG, debug) return False '''Go throught output and see if we can find the profile identifier (key)''' iterator1 = 0 keyoutput = [] keyfound = False for line in output: '''We found the profile identifier''' if re.search("^" + key + ":$", line.strip()): keyfound = True ''''Put all output after the identifier line into a new list''' temp = output[iterator1 + 1:] iterator2 = 0 '''Go through this new list and look for where the payload section starts. The rest of the output gets stored in the keyout list''' for line in temp: if re.search("^Payload Data:", line.strip()): temp = temp[iterator2 + 1:] keyoutput = temp break else: iterator2 += 1 if keyoutput: break else: iterator1 += 1 '''Check to see if we ever found the identifier (key). If not, return False''' if not keyfound: debug = "Key: " + key + " was never found\n" self.logger.log(LogPriority.DEBUG, debug) return False '''keyoutput should just contain lines after Payload Data line''' if keyoutput: payloadblocktemp = [] '''This next loop is getting everything inside the payload section stopping before the next identifier''' for line in keyoutput: if not re.search(".*:", line): line = re.sub("\s+", "", line) payloadblocktemp.append(line) else: break payloadblock = [] i = 0 dontadd = False '''This loop is to clean up the output and squash together any consecutive lines that are blank values inside {} or ()''' while i < len(payloadblocktemp): if dontadd: i += 1 dontadd = False continue '''The next two if statements check to see if two consecutive lines represent an empty dictionary or tuple. If so we want to combine these into one line without the ; at the end''' if re.search("\{$", payloadblocktemp[i]): try: if re.search("\};$", payloadblocktemp[i + 1]): dontadd = True line = re.sub(";$", "", payloadblocktemp[i + 1]) payloadblock.append(payloadblocktemp[i] + line) else: payloadblock.append(payloadblocktemp[i]) except IndexError: debug = "File in bad format, fix will install profile\n" self.logger.log(LogPriority.DEBUG, debug) return False elif re.search("\($", payloadblocktemp[i]): try: if re.search("\);$", payloadblocktemp[i + 1]): dontadd = True line = re.sub(";$", "", payloadblocktemp[i + 1]) payloadblock.append(payloadblocktemp[i] + line) else: payloadblock.append(payloadblocktemp[i]) except IndexError: debug = "File in bad format, fix will install profile\n" self.logger.log(LogPriority.DEBUG, debug) return False else: payloadblock.append(payloadblocktemp[i]) i += 1 '''k is the key inside val variable (e.g. allowsimple) and v is the value, in this example, a list (e.g. ["1", "bool"])''' for k, v, in val.iteritems(): if isinstance(v, list): retval = self.checkSimple(k, v, payloadblock) elif isinstance(v, tuple): retval = self.checkTuple(k, v, payloadblock) elif isinstance(v, dict): retval = self.checkDict(k, v, payloadblock) if not retval: return False else: if not val: return True else: debug = "There was no Payload Data for key: " + key + "\n" self.logger.log(LogPriority.DEBUG, debug) return False return retval def checkSimple(self, k, v, payloadblock): ''' @summary: Method that checks payloadblock contents for k (key) and associated v (value) @author: dwalker @param k: Not to be confused with the key in the calling method which was our identifier before the payload. This key is now the key in the inner dictionary passed through as val from the calling method @param v: Not to be confused with the value in the calling method which was our inner dictionary passed through as val. This val is now the list associated with our k value. @param payloadblock: A list of lines from our payload portion of the output from the system_profiler command @return: bool - True or False ''' founditem = False retval = True unsecure = False debug = "" for line in payloadblock: if re.search("^" + k + " = ", line.strip()): founditem = True temp = line.strip().split("=") try: if temp[1]: '''Remove any arbitrary whitespace''' temp[1] = re.sub("\s", "", temp[1]) '''Remove semicolon at end if exists''' temp[1] = re.sub(";$", "", temp[1]) '''If the second value inside the list v is the word bool, then we want to make sure that our value found after the = in our output matches what we're expecting in v[0] which is either going to be a 1 or 0''' if v[1] == "bool": if str(temp[1].strip()) != v[0]: debug += "Key: " + k + " doesn't " + \ "contain the correct boolean " + \ "value\n" unsecure = True break '''If the second value inside the list v is the word int, then we want to make sure that our value found after the = in our output matches what we're expecting in v[0] which could be any numerical integer. Additionally, if it's "int", there will be a third value inside the list v (v[2]) which will contain either the word "more" or "less". More indicates that if the values don't match but the value in our output is a greater integer value than what we're expecting, then it's still ok and vice versa with the less keyword.''' elif v[1] == "int": if v[2] == "more": if int(temp[1].strip()) < int(v[0]): debug += "Key: " + k + " doesn't " + \ "contain the correct integer " + \ "value\n" unsecure = True break elif v[2] == "less": if int(temp[1].strip()) > int(v[0]): debug += "Key: " + k + " doesn't " + \ "contain the correct integer " + \ "value\n" unsecure = True break '''If the second value inside the list v is the word string, then we want to make sure that our value found after the = in our output matches what we're expecting in v[0] which could be any string.''' elif v[1] == "string": if temp[1].strip() != v[0]: debug += "Key: " + k + " doesn't " + \ "contain the correct string value\n" unsecure = True break except IndexError: debug += "Profile in bad format\n" break if not founditem: debug = "Key: " + k + " not found\n" retval = False if unsecure: debug = "Key: " + k + " found but had an incorrect value\n" retval = False if debug: self.logger.log(LogPriority.DEBUG, debug) return retval def checkTuple(self, k, v, payloadblock): ''' @summary: Method that checks payloadblock contents for k (key) and associated v (value) @author: dwalker @param k: Not to be confused with the key in the calling method which was our identifier before the payload. This key is now the key in the inner dictionary passed through as val from the calling method @param v: Not to be confused with the value in the calling method which was our inner dictionary passed through as val. This val is now the tuple associated with our k value. @param payloadblock: A list of lines from our payload portion of the output from the system_profiler command @return: bool - True or False ''' retval = True iterator = 0 temp, temp2 = [], [] for line in payloadblock: if re.search("^" + k + "=", line): if re.search("\(\)$", line): if str(v) == "()": return True else: return False elif re.search("\($", line): temp = payloadblock[iterator + 1:] break else: iterator += 1 iterator = 0 for line in temp: if re.search("\)\;", line): temp2 = temp[:iterator] else: iterator += 1 if temp2: temp = temp2 if temp: replaceables = [] for line in temp: if re.search("\,$", line): line = re.sub("\,$", "", line) replaceables.append(line) else: replaceables.append(line) if replaceables: temp = replaceables removeables = [] for line in temp: if line in v: removeables.append(line) if removeables: v = list(v) for item in removeables: v.remove(item) temp.remove(item) v = tuple(v) if v: '''There are still items left so we didn't find them all''' debug = "The following tuple items weren't found for the key " + k + "\n" debug += str(v) + "\n" self.logger.log(LogPriority.DEBUG, debug) retval = False if temp: debug = "The following items were in the output that shouldn't have been\n" for item in temp: if not re.search("\)\;|\($", item): debug += str(temp) + "\n" self.logger.log(LogPriority.DEBUG, debug) retval = False else: debug = "key " + k + " wasn't found\n" self.logger.log(LogPriority.DEBUG, debug) retval = False return retval def checkDict(self, k, v, payloadblock): ''' @summary: Method that checks payloadblock contents for k (key) and associated v (value) @author: dwalker @param k: Not to be confused with the key in the calling method which was our identifier before the payload. This key is now the key in the inner dictionary passed through as val from the calling method @param v: Not to be confused with the value in the calling method which was our inner dictionary passed through as val. This val is now the dict associated with our k value. @param payloadblock: A list of lines from our payload portion of the output from the system_profiler command @return: bool - True or False ''' retval = True iterator = 0 for line in payloadblock: if re.search("^" + k + "=", line): if re.search("\{\}$", line): if str(v) == "{}": return True else: return False elif re.search("\{$", line): temp = payloadblock[iterator + 1:] break else: iterator += 1 for k2, v2 in v.iteritems(): if isinstance(v2, list): retval = self.checkSimple(k2, v2, temp) elif isinstance(v2, tuple): retval = self.checkTuple(k2, v2, temp) elif isinstance(v2, dict): retval = self.checkDict(k2, v2, temp) if not retval: return False return retval def setUndoCmd(self, undocmd): ''' @summary: Mutator method to set self.undocmd to the passed in undo command. @author: dwalker @param undocmd: undo command passed through from update method ''' self.undocmd = undocmd def setInstallCmd(self, installcmd): ''' @summary: Mutator method to set self.installcmd to thev passed in install command. @author: dwalker @param installcmd: install command passed through from update method ''' self.installcmd = installcmd def getUndoCmd(self): ''' @summary: Accessor method to retrieve self.undocmd @author: dwalker @return: self.undocmd ''' return self.undocmd def getInstallCmd(self): ''' @summary: Accessor method to retrieve self.installcmd @author: dwalker @return: self.installcmd ''' return self.installcmd def update(self): ''' @summary: Method to set the install command for installing the profile for the fix method and set the remove command for removing the profile for the undo method in upper implementing classes @author: dwalker @return: bool - True ''' cmd = ["/usr/bin/profiles", "-I", "-F", self.path] self.setInstallCmd(cmd) cmd = ["/usr/bin/profiles", "-R", "-F", self.path] self.setUndoCmd(cmd) return True def commit(self): ''' @summary: Method that performs the install command to install the appropriate profile for the calling rule. @author: dwalker @return: bool - True or False ''' self.ch = CommandHelper(self.logger) if self.installcmd: if not self.ch.executeCommand(self.installcmd): return False elif self.ch.getReturnCode() != 0: return False else: return True else: return False return True
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 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": ch = CommandHelper(self.logger) command = event["command"] ch.executeCommand(command) if ch.getReturnCode() != 0: self.detailedresults = "couldn\'t run the command \ to undo\n" self.logger.log(LogPriority.DEBUG, self.detailedresults) elif event["eventtype"] == "commandstring": ch = CommandHelper(self.logger) command = event["command"] ch.executeCommand(command) if ch.getReturnCode() != 0: self.detailedresults = "couldn\'t run the command \ to undo\n" self.logger.log(LogPriority.DEBUG, self.detailedresults) elif event["eventtype"] == "creation": os.remove(event["filepath"]) 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
class SHsystemctl(ServiceHelperTemplate): """ SHsystemctl is the Service Helper for systems using the systemctl command to configure services. (Fedora and future RHEL and variants) """ def __init__(self, environment, logdispatcher): """ Constructor """ super(SHsystemctl, self).__init__(environment, logdispatcher) self.environment = environment self.logdispatcher = logdispatcher self.ch = CommandHelper(self.logdispatcher) self.localize() def localize(self): """ @return: """ systemctl_paths = ["/usr/bin/systemctl", "/bin/systemctl"] self.sysctl = "" for sp in systemctl_paths: if os.path.exists(sp): self.sysctl = sp break if not self.sysctl: raise IOError("Cannot find systemctl utility on this system!") # do not attempt to manipulate any service which has a status in this list self.handsoff = ["static", "transient", "generated", "masked", "masked-runtime"] def disableService(self, service, **kwargs): """ Disables the service and terminates it if it is running. @param service: string; Name of the service to be disabled @return: disabled @rtype: bool @author: ??? @change: Breen Malmberg - 04/10/2019 - method refactor; doc string edit; logging edit """ disabled = True self.ch.executeCommand(self.sysctl + " disable " + service) retcode = self.ch.getReturnCode() if retcode != 0: disabled = False errmsg = self.ch.getErrorString() self.logdispatcher.log(LogPriority.DEBUG, errmsg) if not self.stopService(service): disabled = False return disabled def enableService(self, service, **kwargs): """ Enables a service and starts it if it is not running as long as we are not in install mode @param service: string; Name of the service to be disabled @return: enabled @rtype: bool @author: ??? @change: Breen Malmberg - 04/10/2019 - method refactor; doc string edit; logging edit """ enabled = True if self.getServiceStatus(service, **kwargs) in self.handsoff: enabled = False return enabled self.ch.executeCommand(self.sysctl + " enable " + service) retcode = self.ch.getReturnCode() if retcode != 0: enabled = False errmsg = self.ch.getErrorString() self.logdispatcher.log(LogPriority.DEBUG, errmsg) return enabled def auditService(self, service, **kwargs): """ Checks the status of a service and returns a bool indicating whether or not the service is configured to run or not. @param service: string; Name of the service to audit @return: enabled @rtype: bool """ enabled = False self.ch.executeCommand(self.sysctl + " is-enabled " + service) if self.ch.findInOutput("not a native service"): self.logdispatcher.log(LogPriority.DEBUG, "Attempted to audit a non-systemd service with systemctl commands") return enabled elif self.ch.findInOutput("enabled"): enabled = True return enabled def isRunning(self, service, **kwargs): """ Check to see if a service is currently running. The enable service uses this so that we're not trying to start a service that is already running. @param service: string; name of service to check @return: running @rtype: bool @author: ??? @change: Breen Malmberg - 04/10/2019 - method refactor; doc string edit; debug logging edit """ running = True inactive_keys = ["inactive", "unknown"] self.ch.executeCommand(self.sysctl + " is-active " + service) for k in inactive_keys: if self.ch.findInOutput(k): running = False return running def reloadService(self, service, **kwargs): """ Reload (HUP) a service so that it re-reads it's config files. Called by rules that are configuring a service to make the new configuration active. @param service: string; Name of the service to reload @return: success @rtype: bool @author: ??? @change: Breen Malmberg - 04/10/2019 - method refactor; doc string edit; debug logging edit """ success = True if self.getServiceStatus(service, **kwargs) in self.handsoff: success = False return success self.ch.executeCommand(self.sysctl + " reload-or-restart " + service) retcode = self.ch.getReturnCode() if retcode != 0: success = False errmsg = self.ch.getErrorString() self.logdispatcher.log(LogPriority.DEBUG, errmsg) if not self.isRunning(service): success = False return success def listServices(self, **kwargs): """ Return a list containing strings that are service names. @return: service_list @rtype: bool @author: ??? @change: Breen Malmberg - 04/10/2019 - method refactor; debug logging edit; doc string edit """ service_list = [] # list all installed, service-type service units on the system self.ch.executeCommand(self.sysctl + " -a -t service --no-pager list-unit-files") output = self.ch.getOutput() for line in output: try: service_list.append(line.split()[0]) except IndexError: pass except: raise if not service_list: errmsg = self.ch.getErrorString() if errmsg: self.logdispatcher.log(LogPriority.DEBUG, errmsg) return service_list def startService(self, service, **kwargs): """ start given service @param service: @param kwargs: @return: started @rtype: bool @author: Breen Malmberg """ started = True if self.getServiceStatus(service, **kwargs) in self.handsoff: started = False return started self.ch.executeCommand(self.sysctl + " start " + service) retcode = self.ch.getReturnCode() if retcode != 0: started = False errmsg = self.ch.getErrorString() self.logdispatcher.log(LogPriority.DEBUG, errmsg) return started def stopService(self, service, **kwargs): """ stop given service @param service: @param kwargs: @return: stopped @rtype: bool @author: Breen Malmberg """ stopped = True if not self.isRunning(service): return stopped # nothing to do if self.getServiceStatus(service, **kwargs) in self.handsoff: stopped = False return stopped else: self.ch.executeCommand(self.sysctl + " stop " + service) retcode = self.ch.getReturnCode() if retcode != 0: stopped = False errmsg = self.ch.getErrorString() self.logdispatcher.log(LogPriority.DEBUG, errmsg) return stopped def getServiceStatus(self, service, **kwargs): """ return is-enabled status output possible return values: enabled enabled-runtime linked linked-runtime masked masked-runtime static indirect disabled generated transient unknown (custom status defined in STONIX; not generated by systemctl) @param service: @param kwargs: @return: status @rtype: string @author: Breen Malmberg """ status = "" known_statuses = ["enabled", "enabled-runtime", "linked", "linked-runtime", "masked", "masked-runtime", "static", "indirect", "disabled", "generated", "transient"] self.ch.executeCommand(self.sysctl + " is-enabled " + service) output = self.ch.getOutputString() try: if len(output.split()) == 1: status = str(output) else: status = str(output.split()[0]) except IndexError: pass except: raise if status not in known_statuses: status = "unknown" elif not isinstance(status, basestring): status = "unknown" if status in self.handsoff: self.logdispatcher.log(LogPriority.DEBUG, "Status of service: " + service + " indicates it is either protected, required or immutable. Will not perform operation on this service!") return status def getStartCommand(self, service): ''' retrieve the start command. Mostly used by event recording @return: string - start command @author: dwalker ''' return self.sysctl + " start " + service def getStopCommand(self, service): ''' retrieve the stop command. Mostly used by event recording @return: string - stop command @author: dwalker ''' return self.sysctl + " stop " + service def getEnableCommand(self, service): ''' retrieve the enable command. Mostly used by event recording @return: string - enable command @author: dwalker ''' return self.sysctl + " enable " + service def getDisableCommand(self, service): ''' retrieve the start command. Mostly used by event recording @return: string - disable command @author: dwalker ''' return self.sysctl + " disable " + service
class Dnf(object): '''The template class that provides a framework that must be implemented by all platform specific pkgmgr classes. Specifically for Fedora :version: :author:Derek T Walker 08-13-2015''' def __init__(self, logger): self.logger = logger self.detailedresults = "" self.ch = CommandHelper(self.logger) self.install = "/usr/bin/dnf install -y " self.remove = "/usr/bin/dnf remove -y " self.search = "/usr/bin/dnf search " self.rpm = "/bin/rpm -q " ############################################################################### def installpackage(self, package): '''Install a package. Return a bool indicating success or failure. @param string package : Name of the package to be installed, must be recognizable to the underlying package manager. @return bool : @author''' try: installed = False self.ch.executeCommand(self.install + package) if self.ch.getReturnCode() == 0: installed = True self.detailedresults = package + \ " pkg installed successfully\n" else: self.detailedresults = package + " pkg not able to install\n" self.logger.log(LogPriority.DEBUG, self.detailedresults) return installed except(KeyboardInterrupt, SystemExit): raise except Exception: self.detailedresults = traceback.format_exc() self.logger.log(LogPriority.ERROR, self.detailedresults) raise(self.detailedresults) ############################################################################### def removepackage(self, package): '''Remove a package. Return a bool indicating success or failure. @param string package : Name of the package to be removed, must be recognizable to the underlying package manager. @return bool : @author''' try: removed = False self.ch.executeCommand(self.remove + package) if self.ch.getReturnCode() == 0: removed = True self.detailedresults += package + " pkg removed successfully\n" else: self.detailedresults += package + \ " pkg not able to be removed\n" self.logger.log(LogPriority.DEBUG, self.detailedresults) return removed except(KeyboardInterrupt, SystemExit): raise except Exception: self.detailedresults = traceback.format_exc() self.logger.log(LogPriority.ERROR, self.detailedresults) raise(self.detailedresults) ############################################################################### def checkInstall(self, package): '''Check the installation status of a package. Return a bool; True if the package is installed. @param: string package : Name of the package whose installation status is to be checked, must be recognizable to the underlying package manager. @return: bool : @author: dwalker''' try: found = False self.ch.executeCommand(self.rpm + package) if self.ch.getReturnCode() == 0: found = True self.detailedresults += package + " pkg found\n" else: self.detailedresults += package + " pkg not found\n" self.logger.log(LogPriority.DEBUG, self.detailedresults) return found except(KeyboardInterrupt, SystemExit): raise except Exception: self.detailedresults = traceback.format_exc() self.logger.log(LogPriority.ERROR, self.detailedresults) raise(self.detailedresults) ############################################################################### def checkAvailable(self, package): try: found = False self.ch.executeCommand(self.search + package) output = self.ch.getOutputString() if re.search("no matches found", output.lower()): self.detailedresults += package + " pkg is not available " + \ " or may be misspelled\n" elif re.search("matched", output.lower()): self.detailedresults += package + " pkg is available\n" found = True self.logger.log(LogPriority.DEBUG, self.detailedresults) return found except(KeyboardInterrupt, SystemExit): raise except Exception: self.detailedresults = traceback.format_exc() self.logger.log(LogPriority.ERROR, self.detailedresults) raise(self.detailedresults) ############################################################################### def getPackageFromFile(self, filename): '''Returns the name of the package that provides the given filename/path. @param: string filename : The name or path of the file to resolve @return: string name of package if found, None otherwise @author: Eric Ball ''' try: self.ch.executeCommand(self.rpm + "-f " + filename) if self.ch.getReturnCode() == 0: return self.ch.getOutputString() else: return None except(KeyboardInterrupt, SystemExit): raise except Exception: self.detailedresults = traceback.format_exc() self.logger.log(LogPriority.ERROR, self.detailedresults) raise(self.detailedresults) ############################################################################### def getInstall(self): return self.install ############################################################################### def getRemove(self): return self.remove
class Zypper(object): """The template class that provides a framework that must be implemented by all platform specific pkgmgr classes. @author: Derek T Walker @change: 2012/08/08 dwalker - Original Implementation @change: 2014/09/10 dkennel - Added -n option to search command string @change: 2014/12/24 bemalmbe - fixed a typo in the old search string @change: 2014/12/24 bemalmbe - changed search strings to be match exact and search for installed or available separately @change: 2014/12/24 bemalmbe - fixed multiple pep8 violations @change: 2015/08/20 eball - Added getPackageFromFile and self.rpm var """ def __init__(self, logger): self.logger = logger self.detailedresults = "" self.ch = CommandHelper(self.logger) self.install = "/usr/bin/zypper --non-interactive install " self.remove = "/usr/bin/zypper --non-interactive remove " self.searchi = "/usr/bin/zypper --non-interactive search --match-exact -i " self.searchu = "/usr/bin/zypper --non-interactive search --match-exact -u " self.rpm = "/bin/rpm -q " ############################################################################### def installpackage(self, package): """Install a package. Return a bool indicating success or failure. @param string package : Name of the package to be installed, must be recognizable to the underlying package manager. @return: bool @author: dwalker @change: 12/24/2014 - bemalmbe - fixed method doc string formatting """ try: installed = False self.ch.executeCommand(self.install + package) output = self.ch.getOutputString() if self.ch.getReturnCode() == 0: if search("Abort, retry, ignore", output): self.detailedresults += "There is an error contacting " + "one or more repos, aborting\n" return False self.detailedresults += package + " pkg installed successfully\n" installed = True else: self.detailedresults += package + " pkg not able to install\n" self.logger.log(LogPriority.INFO, self.detailedresults) return installed except (KeyboardInterrupt, SystemExit): raise except Exception: self.detailedresults = traceback.format_exc() self.logger.log(LogPriority.ERROR, self.detailedresults) ############################################################################### def removepackage(self, package): """Remove a package. Return a bool indicating success or failure. @param string package : Name of the package to be removed, must be recognizable to the underlying package manager. @return: bool @author: dwalker @change: 12/24/2014 - bemalmbe - fixed method doc string formatting @change: 12/24/2014 - bemalmbe - fixed an issue with var 'removed' not being initialized before it was called """ removed = False try: self.ch.executeCommand(self.remove + package) output = self.ch.getOutputString() if self.ch.getReturnCode() == 0: if search("Abort, retry, ignore", output): self.detailedresults += "There is an error contacting " + "one or more repos, aborting\n" return False self.detailedresults += package + " pkg removed successfully\n" removed = True else: self.detailedresults += package + " pkg not able to be removed\n" self.logger.log(LogPriority.INFO, self.detailedresults) return removed except (KeyboardInterrupt, SystemExit): raise except Exception: self.detailedresults = traceback.format_exc() self.logger.log(LogPriority.ERROR, self.detailedresults) ############################################################################### def checkInstall(self, package): """ Check the installation status of a package. Return a bool; True if the package is installed. @param string package : Name of the package whose installation status is to be checked, must be recognizable to the underlying package manager. @return: bool @author: dwalker @change: 12/24/2014 - bemalmbe - fixed method doc string formatting @change: 12/24/2014 - bemalmbe - changed var name 'found' to 'installed' @change: 12/24/2014 - bemalmbe - now uses correct search syntax @change: 12/24/2014 - bemalmbe - removed detailedresults update on 'found but not installed' as this no longer applies to this method """ try: installed = False self.ch.executeCommand(self.searchi + package) if self.ch.getReturnCode() == 0: output = self.ch.getOutput() outputStr = self.ch.getOutputString() if search("Abort, retry, ignore", outputStr): self.detailedresults += "There is an error contacting " + "one or more repos, aborting\n" return False for line in output: if search(package, line): installed = True if installed: self.detailedresults += package + " pkg is installed\n" self.logger.log(LogPriority.DEBUG, self.detailedresults) return True else: installed = False self.detailedresults += ( package + " pkg not found or may be \ misspelled\n" ) self.logger.log(LogPriority.DEBUG, self.detailedresults) return False except (KeyboardInterrupt, SystemExit): raise except Exception: self.detailedresults = traceback.format_exc() self.logger.log(LogPriority.ERROR, self.detailedresults) ############################################################################### def checkAvailable(self, package): """ check if given package is available to install on the current system @param: package string name of package to search for @return: bool @author: dwalker @change: 12/24/2014 - bemalmbe - added method documentation @change: 12/24/2014 - bemalmbe - changed var name 'found' to 'available' @change: 12/24/2014 - bemalmbe - fixed search syntax and updated search variable name """ try: available = False self.ch.executeCommand(self.searchu + package) if self.ch.getReturnCode() == 0: output = self.ch.getOutput() for line in output: if search(package, line): available = True if available: self.detailedresults += package + " pkg is available\n" else: self.detailedresults += package + " pkg is not available\n" else: self.detailedresults = ( package + " pkg not found or may be \ misspelled\n" ) self.logger.log(LogPriority.INFO, self.detailedresults) return available except (KeyboardInterrupt, SystemExit): raise except Exception: self.detailedresults = traceback.format_exc() self.logger.log(LogPriority.ERROR, self.detailedresults) ############################################################################### def getPackageFromFile(self, filename): """Returns the name of the package that provides the given filename/path. @param: string filename : The name or path of the file to resolve @return: string name of package if found, None otherwise @author: Eric Ball """ try: self.ch.executeCommand(self.rpm + "-f " + filename) if self.ch.getReturnCode() == 0: return self.ch.getOutputString() else: return None except (KeyboardInterrupt, SystemExit): raise except Exception: self.detailedresults = traceback.format_exc() self.logger.log(LogPriority.ERROR, self.detailedresults) raise (self.detailedresults) ############################################################################### def getInstall(self): """ return the install command string for the zypper pkg manager @return: string @author: dwalker @change: 12/24/2014 - bemalmbe - added method documentation """ return self.install ############################################################################### def getRemove(self): """ return the uninstall/remove command string for the zypper pkg manager @return: string @author: dwalker @change: 12/24/2014 - bemalmbe - added method documentation """ return self.remove
def __init__(self,logger): self.logger = logger self.detailedresults = "" self.ch = CommandHelper(self.logger) self.install = "/usr/sbin/pkg_add -r -f " self.remove = "/usr/sbin/pkg_delete "
class Zypper(object): ''' The template class that provides a framework that must be implemented by all platform specific pkgmgr classes. @author: Derek T Walker @change: 2012/08/08 Derek Walker - Original Implementation @change: 2014/09/10 dkennel - Added -n option to search command string @change: 2014/12/24 Breen Malmberg - fixed a typo in the old search string; fixed multiple pep8 violations; changed search strings to be match exact and search for installed or available separately @change: 2015/08/20 eball - Added getPackageFromFile and self.rpm var @change: 2016/08/02 eball - Moved checkInstall return out of else block @change: 2017/04/19 Breen Malmberg - refactored multiple methods; cleaned up doc strings; added logging; added two methods: Update and checkUpdate; removed detailedresults reset in __init__ (this should always be handled in the calling rule); replaced detailedresults instances with logging; added the flag "--quiet" to the install variable ''' def __init__(self, logger): self.logger = logger self.ch = CommandHelper(self.logger) self.zyploc = "/usr/bin/zypper" self.install = self.zyploc + " --non-interactive --quiet install " self.remove = self.zyploc + " --non-interactive remove " self.searchi = self.zyploc + " --non-interactive search --match-exact -i " self.searchu = self.zyploc + " --non-interactive search --match-exact -u " self.updates = self.zyploc + " lu " self.upzypp = self.zyploc + " up " self.rpm = "/usr/bin/rpm -q " self.pkgtype = "zypper" def installpackage(self, package): ''' Install a package. Return a bool indicating success or failure. @param package: string; Name of the package to be installed, must be recognizable to the underlying package manager. @return: installed @rtype: bool @author: Derek Walker @change: Breen Malmberg - 12/24/2014 - fixed method doc string formatting @change: Breen Malmberg - 10/1/2018 - added check for package manager lock and retry loop ''' installed = True maxtries = 12 trynum = 0 while psRunning("zypper"): trynum += 1 if trynum == maxtries: self.logger.log(LogPriority.DEBUG, "Timed out while attempting to install package due to zypper package manager being in-use by another process.") installed = False return installed else: self.logger.log(LogPriority.DEBUG, "zypper package manager is in-use by another process. Waiting for it to be freed...") time.sleep(5) try: try: self.ch.executeCommand(self.install + package) retcode = self.ch.getReturnCode() if retcode != 0: raise repoError('zypper', retcode) except repoError as repoerr: if not repoerr.success: installed = False if installed: self.logger.log(LogPriority.DEBUG, "Package " + str(package) + " installed successfully") else: self.logger.log(LogPriority.DEBUG, "Failed to install package " + str(package)) except Exception: raise return installed def removepackage(self, package): ''' Remove a package. Return a bool indicating success or failure. @param package: string; Name of the package to be removed, must be recognizable to the underlying package manager. @return: removed @rtype: bool @author: Derek Walker @change: 12/24/2014 - Breen Malmberg - fixed method doc string formatting; fixed an issue with var 'removed' not being initialized before it was called ''' removed = True maxtries = 12 trynum = 0 while psRunning("zypper"): trynum += 1 if trynum == maxtries: self.logger.log(LogPriority.DEBUG, "Timed out while attempting to remove package due to zypper package manager being in-use by another process.") removed = False return removed else: self.logger.log(LogPriority.DEBUG, "zypper package manager is in-use by another process. Waiting for it to be freed...") time.sleep(5) try: try: self.ch.executeCommand(self.remove + package) retcode = self.ch.getReturnCode() if retcode != 0: raise repoError('zypper', retcode) except repoError as repoerr: if not repoerr.success: removed = False if removed: self.logger.log(LogPriority.DEBUG, "Package " + str(package) + " was removed successfully") else: self.logger.log(LogPriority.DEBUG, "Failed to remove package " + str(package)) except Exception: raise return removed def checkInstall(self, package): ''' Check the installation status of a package. Return a bool; True if the package is installed. @param string package : Name of the package whose installation status is to be checked, must be recognizable to the underlying package manager. @return: bool @author: Derek Walker @change: 12/24/2014 - Breen Malmberg - fixed method doc string formatting @change: 12/24/2014 - Breen Malmberg - changed var name 'found' to 'installed' @change: 12/24/2014 - Breen Malmberg - now uses correct search syntax @change: 12/24/2014 - Breen Malmberg - removed detailedresults update on 'found but not installed' as this no longer applies to this method ''' installed = True errstr = "" maxtries = 12 trynum = 0 while psRunning("zypper"): trynum += 1 if trynum == maxtries: self.logger.log(LogPriority.DEBUG, "Timed out while attempting to check status of package due to zypper package manager being in-use by another process.") installed = False return installed else: self.logger.log(LogPriority.DEBUG, "zypper package manager is in-use by another process. Waiting for it to be freed...") time.sleep(5) try: try: self.ch.executeCommand(self.searchi + package) retcode = self.ch.getReturnCode() errstr = self.ch.getErrorString() if retcode != 0: raise repoError('zypper', retcode, str(errstr)) except repoError as repoerr: if not repoerr.success: installed = False if installed: self.logger.log(LogPriority.DEBUG, " Package " + str(package) + " is installed") else: self.logger.log(LogPriority.DEBUG, " Package " + str(package) + " is NOT installed") except Exception: raise return installed def checkAvailable(self, package): ''' check if given package is available to install on the current system @param: package string name of package to search for @return: bool @author: Derek Walker @change: 12/24/2014 - Breen Malmberg - added method documentation @change: 12/24/2014 - Breen Malmberg - changed var name 'found' to 'available' @change: 12/24/2014 - Breen Malmberg - fixed search syntax and updated search variable name @change: Breen Malmberg - 5/1/2017 - replaced detailedresults with logging; added parameter validation ''' available = True maxtries = 12 trynum = 0 while psRunning("zypper"): trynum += 1 if trynum == maxtries: self.logger.log(LogPriority.DEBUG, "Timed out while attempting to check availability of package, due to zypper package manager being in-use by another process.") available = False return available else: self.logger.log(LogPriority.DEBUG, "zypper package manager is in-use by another process. Waiting for it to be freed...") time.sleep(5) try: try: self.ch.executeCommand(self.searchu + package) retcode = self.ch.getReturnCode() errstr = self.ch.getErrorString() output = self.ch.getOutput() if retcode != 0: raise repoError('zypper', retcode, str(errstr)) else: for line in output: if re.search(package, line): available = True except repoError as repoerr: if not repoerr.success: self.logger.log(LogPriority.WARNING, str(repoerr)) return False if available: self.logger.log(LogPriority.DEBUG, "Package " + str(package) + " is available to install") else: self.logger.log(LogPriority.DEBUG, "Package " + str(package) + " is NOT available to install") except Exception: raise return available def checkUpdate(self, package=""): ''' check for available updates for specified package. if no package is specified, then check for updates to the entire system. @param package: string; name of package to check @return: updatesavail @rtype: bool @author: Breen Malmberg ''' # zypper does not have a package-specific list updates mechanism # you have to list all updates or nothing updatesavail = True try: try: if package: self.ch.executeCommand(self.updates + " | grep " + package) else: self.ch.executeCommand(self.updates) retcode = self.ch.getReturnCode() errstr = self.ch.getErrorString() if retcode != 0: raise repoError('zypper', retcode, str(errstr)) except repoError as repoerr: if not repoerr.success: self.logger.log(LogPriority.WARNING, str(errstr)) updatesavail = False if package: if not updatesavail: self.logger.log(LogPriority.DEBUG, "No updates are available for package " + str(package)) else: self.logger.log(LogPriority.DEBUG, "Updates are available for package " + str(package)) else: if not updatesavail: self.logger.log(LogPriority.DEBUG, "No updates are available") else: self.logger.log(LogPriority.DEBUG, "Updates are available") except Exception: raise return updatesavail def Update(self, package=""): ''' update a specified package if no package name is specified, then update all packages on the system @param package: string; name of package to update @return: updated @rtype: bool @author: Breen Malmberg ''' updated = True try: try: self.ch.executeCommand(self.upzypp + package) retcode = self.ch.getReturnCode() errstr = self.ch.getErrorString() if retcode != 0: raise repoError('zypper', retcode, str(errstr)) except repoError as repoerr: if not repoerr.success: self.logger.log(LogPriority.WARNING, str(errstr)) updated = False except Exception: raise return updated def getPackageFromFile(self, filename): '''Returns the name of the package that provides the given filename/path. @param: string filename : The name or path of the file to resolve @return: string name of package if found, None otherwise @author: Eric Ball ''' packagename = "" try: try: self.ch.executeCommand(self.rpm + "-f " + filename) retcode = self.ch.getReturnCode() errstr = self.ch.getErrorString() outputstr = self.ch.getOutputString() if retcode != 0: raise repoError('zypper', retcode, str(errstr)) # return "" else: packagename = outputstr except repoError as repoerr: if not repoerr.success: self.logger.log(LogPriority.WARNING, str(errstr)) else: packagename = outputstr except Exception: raise return packagename def getInstall(self): ''' return the install command string for the zypper pkg manager @return: string @author: Derek Walker @change: 12/24/2014 - Breen Malmberg - added method documentation ''' return self.install def getRemove(self): ''' return the uninstall/remove command string for the zypper pkg manager @return: string @author: Derek Walker @change: 12/24/2014 - Breen Malmberg - added method documentation ''' return self.remove
class KVEditor(object): '''The main parent class for The Key Value Editor Class group. Call the validate def to see if the specified values are either present or not based on the intent desired, "present" or "notpresent", where, "present" means the values you set are desired in the configuration file and "notpresent" means the values you set are not desired in the configuration file. If you have a mixture of desired key-values and undesired key-values you must set intent for each time you change intents then setData with the new data. Do not run commit until all''' def __init__(self, stchlgr, logger, kvtype, path, tmpPath, data, intent="", configType="", output=""): ''' KVEditor constructor @param stchlgr: StateChgLogger object @param logger: logger object @param kvtype: Type of key-value file. Valid values: "tagconf", "conf", "defaults", "profiles" @param path: Path to key-value file @param tmpPath: Path to temp file for key-value list @param data: Dict of key-value data @param intent: "present" or "notpresent" @param configType: Specify how the config options are separated. Valid values: "space", "openeq", "closedeq" @param output: Output of profiler command, used only by KVAProfiles ''' self.kvtype = kvtype self.path = path self.tmpPath = tmpPath self.logger = logger self.configType = configType self.data = data self.output = output self.detailedresults = "" self.missing = [] self.fixables = {} self.fixlist = [] self.removeables = {} self.intent = intent self.container = {} self.iditerator = 0 self.idcontainer = [] if self.kvtype == "tagconf": if not self.getPath: return None self.editor = KVATaggedConf.KVATaggedConf(self.path, self.tmpPath, self.intent, self.configType, self.logger) elif self.kvtype == "conf": if not self.getPath: return None self.editor = KVAConf.KVAConf(self.path, self.tmpPath, self.intent, self.configType, self.logger) elif self.kvtype == "defaults": self.editor = KVADefault.KVADefault(self.path, self.logger, self.data) elif self.kvtype == "profiles": self.editor = KVAProfiles.KVAProfiles(self.logger, self.path) else: self.detailedresults = "Not one of the supported kveditor types" self.logger.log(LogPriority.DEBUG, ["KVEditor.__init__", self.detailedresults]) return None def setData(self, data): if data is None: return False elif data == "": return False else: self.data = data return True def getData(self): return self.data def updateData(self, data): self.data = data def setIntent(self, intent): if intent == "present" or intent == "notpresent": self.intent = intent self.editor.setIntent(intent) return True else: return False def getIntent(self): return self.intent def setPath(self, path): if not os.path.exists(path): self.detailedresults = "File path does not exist" self.logger.log(LogPriority.INFO, ["KVEditor", self.detailedresults]) return False else: self.path = path self.editor.setPath(path) return True def getPath(self): if not os.path.exists(self.path): debug = "File path does not exist\n" self.logger.log(LogPriority.DEBUG, debug) return False else: return self.path def setTmpPath(self, tmpPath): self.tmpPath = tmpPath self.editor.setTmpPath(tmpPath) return True def getTmpPath(self): return self.tmpPath def getType(self): return self.kvtype def setConfigType(self, configType): self.configType = configType self.editor.setConfigType(configType) return True def getConfigType(self): return self.configType def validate(self): try: status = False if self.kvtype == "defaults": status = self.validateDefaults() elif self.kvtype == "plist": status = self.validatePlist() elif self.kvtype == "conf": status = self.validateConf() elif self.kvtype == "tagconf": status = self.validateTag() elif self.kvtype == "profiles": status = self.validateProfiles() else: status = "invalid" debug = "KVEditor is returning " + str(status) + " back to " + \ "KVEditorStonix.report()\n" self.logger.log(LogPriority.DEBUG, debug) return status except(KeyboardInterrupt, SystemExit): raise except Exception: raise def update(self): try: status = False if self.kvtype == "defaults": status = self.updateDefaults() elif self.kvtype == "plist": status = self.updatePlist() elif self.kvtype == "conf": status = self.updateConf() elif self.kvtype == "tagconf": status = self.updateTag() elif self.kvtype == "profiles": status = self.updateProfiles() else: status = False debug = "KVEditor is returning " + str(status) + " back to " + \ "KVEditorStonix.fix()\n" self.logger.log(LogPriority.DEBUG, debug) return status except(KeyboardInterrupt, SystemExit): raise except Exception: raise def validateDefaults(self): if isinstance(self.data, dict): if not self.checkDefaults(self.data): return False else: return False if self.editor.validate(): return True else: return False def updateDefaults(self): if self.editor.update(): debug = "KVEditor.updateDefaults() is returning True to " + \ "KVEditor.update()\n" self.logger.log(LogPriority.DEBUG, debug) return True else: debug = "KVEditor.updateDefaults() is returning False to " + \ "KVEditor.update()\n" self.logger.log(LogPriority.DEBUG, debug) return False def checkDefaults(self, data): for k, v in data.iteritems(): if isinstance(v, dict): retval = self.checkDefaults(v) return retval elif isinstance(v, list): if len(v) == 2 or len(v) == 3: return True else: return False else: return False def setCurrentHostbool(self, val): self.editor.currentHost = val def validateConf(self): validate = True if not self.checkConf(): return False if self.intent == "present": for k, v in self.data.iteritems(): retval = self.editor.validate(k, v) if retval == "invalid": validate = "invalid" elif isinstance(retval, list): self.fixables[k] = retval validate = False elif not retval: validate = False self.fixables[k] = v if self.intent == "notpresent": for k, v in self.data.iteritems(): retval = self.editor.validate(k, v) if retval == "invalid": validate = "invalid" elif isinstance(retval, list): self.removeables[k] = retval validate = False elif retval is True: validate = False self.removeables[k] = v if validate == "invalid": debug = "KVEditor.validateConf() is returning invalid to " + \ "KVEditor.validate()\n" elif validate: debug = "KVEditor.validateConf() is returning True to " + \ "KVEditor.validate()\n" else: debug = "KVEditor.validateConf() is returning False to " + \ "KVEditor.validate()\n" self.logger.log(LogPriority.DEBUG, debug) return validate def updateConf(self): if self.fixables or self.removeables: if self.editor.update(self.fixables, self.removeables): debug = "KVEditor.updateConf() is returning True to " + \ "KVEditor.update()\n" self.logger.log(LogPriority.DEBUG, debug) return True else: debug = "KVEditor.updateConf() is returning False to " + \ "KVEditor.update()\n" self.logger.log(LogPriority.DEBUG, debug) return False def checkConf(self): if isinstance(self.data, dict): return True else: return False def validateTag(self): validate = True keyvals = {} if not self.checkTag(): return False if self.intent == "present": for tag in self.data: keyvals = self.editor.getValue(tag, self.data[tag]) if keyvals == "invalid": validate = "invalid" elif isinstance(keyvals, dict): self.fixables[tag] = keyvals validate = False if self.intent == "notpresent": for tag in self.data: keyvals = self.editor.getValue(tag, self.data[tag]) if keyvals == "invalid": validate = "invalid" elif isinstance(keyvals, dict): self.removeables[tag] = keyvals validate = False if validate == "invalid": debug = "KVEditor.validateTag() is returning invalid to " + \ "KVEditor.validate()\n" elif validate: debug = "KVEditor.validateTag() is returning True to " + \ "KVEditor.validate()\n" else: debug = "KVEditor.validateTag() is returning False to " + \ "KVEditor.validate()\n" self.logger.log(LogPriority.DEBUG, debug) return validate def updateTag(self): if self.editor.setValue(self.fixables, self.removeables): debug = "KVEditor.updateTag() is returning True to " + \ "KVEditor.update()\n" self.logger.log(LogPriority.DEBUG, debug) return True else: debug = "KVEditor.updateTag() is returning False to " + \ "KVEditor.update()\n" self.logger.log(LogPriority.DEBUG, debug) return False def checkTag(self): if isinstance(self.data, dict): for tag in self.data: if not isinstance(self.data[tag], dict): return False return True else: return False def validateProfiles(self): ''' @since: 3/10/2016 @author: dwalker @var self.data: A dictionary in the form of {k: {v: ["numberValue", "datatype", "acceptableDeviation"(optional)], v: ["", "", ""], v: ["", "", ""], . . .}} @var: k: The profile sub-identifier e.g. com.apple.mobiledevice.passwordpolicy @var v: The profile data key-value pairs in a dictionary e.g. allowSimple that will appear in the output of the system_profiler command within the first opening brace after the profile sub-identifier. v also contains an associated list containing: [a,b,c] a) the value on the other side of the = sign b) whether that value is an integer(int) or a boolean(bool) c) (optional) whether the value present after the = sign(a), if an int, can be lower(less) or higher(more) in order to detect and represent stringency (see self.data description above). @return: Value returned from validate method in factory sub-class @rtype: bool ''' cmd = ["/usr/sbin/system_profiler", "SPConfigurationProfileDataType"] self.ch = CommandHelper(self.logger) if self.ch.executeCommand(cmd): self.output = self.ch.getOutput() retval = True if self.output: for k, v in self.data.iteritems(): retval = self.editor.validate(self.output, k, v) if not retval: return False else: debug = "There are no profiles installed" self.logger.log(LogPriority.DEBUG, debug) return False return True def updateProfiles(self): retval = self.editor.update() return retval def commit(self): if self.kvtype == "defaults" or self.kvtype == "profiles": retval = self.editor.commit() return retval else: retval = self.editor.commit() self.fixables = {} self.removeables = {} return retval def removekey(self, d, key): r = dict(d) del r[key] return r
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
class SHchkconfig(ServiceHelperTemplate): """ SHchkconfig is the Service Helper for systems using the chkconfig command to configure services. (RHEL up to 6, SUSE, Centos up to 6, etc) @author: David Kennel """ def __init__(self, environment, logdispatcher): """ Constructor """ super(SHchkconfig, self).__init__(environment, logdispatcher) self.environ = environment self.logger = logdispatcher self.initobjs() self.localize() def initobjs(self): """ initialize class objects @return: """ self.ch = CommandHelper(self.logger) def localize(self): """ set base command paths (chkconfig and service) based on OS @return: """ self.svc = "" self.chk = "" chk_paths = ["/sbin/chkconfig", "/usr/sbin/chkconfig"] for cp in chk_paths: if os.path.exists(cp): self.chk = cp break service_paths = ["/sbin/service", "/usr/sbin/service"] for sp in service_paths: if os.path.exists(sp): self.svc = sp break if not self.svc: raise IOError("Could not locate the service utility on this system") if not self.chk: raise IOError("Could not locate the chkconfig utility on this system") def startService(self, service, **kwargs): """ start a given service @param service: string; name of service @param kwargs: @return: success @rtype: bool @author: Breen Malmberg """ success = True self.ch.executeCommand(self.svc + " " + service + " start") retcode = self.ch.getReturnCode() if retcode != 0: success = False if not self.isRunning(service): success = False return success def stopService(self, service, **kwargs): """ stop a given service @param service: @param kwargs: @return: success @rtype: bool @author: Breen Malmberg """ success = True self.ch.executeCommand(self.svc + " " + service + " stop") retcode = self.ch.getReturnCode() if retcode != 0: success = False if self.isRunning(service): success = False return success def disableService(self, service, **kwargs): """ Disables the specified service and stops it if it is running @param service: string; Name of the service to be disabled @return: bool @author: David Kennel @change: Breen Malmberg - 04/10/2019 - method refactor; doc string edit; logging edit """ disabled = True self.ch.executeCommand(self.chk + " " + service + " off") retcode = self.ch.getReturnCode() if retcode != 0: disabled = False if self.auditService(service): disabled = False if not self.stopService(service): disabled = False return disabled def enableService(self, service, **kwargs): """ Enables a service and starts it if it is not running as long as we are not in install mode @param service: string; Name of the service to be enabled @return: enabled @rtype: bool @author: David Kennel @change: Breen Malmberg - 04/10/2019 - """ enabled = True self.ch.executeCommand(self.chk + " " + service + " on") retcode = self.ch.getReturnCode() if retcode != 0: enabled = False if not self.auditService(service): enabled = False if not self.startService(service): enabled = False return enabled def auditService(self, service, **kwargs): """ Checks the status of a service and returns a bool indicating whether or not the service is enabled @param service: string; Name of the service to audit @return: enabled @rtype: bool @author: ??? @change: Breen Malmberg - 04/10/2019 - method refactor; doc string edit; logging edit """ enabled = True if not self.audit_chkconfig_service(service): enabled = False return enabled def audit_chkconfig_service(self, service): """ uses the chkconfig command to check if a given service is enabled or not @return: enabled @rtype: bool @author: Breen Malmberg """ enabled = True self.ch.executeCommand(self.chk + " --list " + service) retcode = self.ch.getReturnCode() if retcode != 0: enabled = False self.logger.log(LogPriority.DEBUG, "Failed to get status of service: " + service) return enabled output = self.ch.getOutputString() if not re.search(":on", output): enabled = False return enabled def isRunning(self, service, **kwargs): """ Check to see if a service is currently running. @param service: string; Name of the service to check @return: running @rtype: bool @author: ??? @change: Breen Malmberg - 04/10/2019 - method refactor; doc string edit; logging edit """ running = True # see: http://refspecs.linuxbase.org/LSB_3.1.0/LSB-generic/LSB-generic/iniscrptact.html success_codes = [0, 1, 2, 3] self.ch.executeCommand(self.svc + " " + service + " status") retcode = self.ch.getReturnCode() if retcode not in success_codes: running = False self.logger.log(LogPriority.DEBUG, "Command error while getting run status of service: " + service) return running outputlines = self.ch.getOutput() # need to parse for either sysv or systemd output if not self.parse_running(outputlines): running = False return running def parse_running(self, outputlines): """ check whether given service is running, with the service command this is the older (classic) systemV case @param outputlines: list; list of strings to search @return: running @rtype: bool @author: Breen Malmberg """ running = True systemctl_locations = ["/usr/bin/systemctl", "/bin/systemctl"] if any(os.path.exists(sl) for sl in systemctl_locations): searchterms = ["Active:\s+inactive", "Active:\s+unknown"] else: searchterms = ["is stopped", "hook is not installed", "is not running"] for line in outputlines: if any(re.search(st, line) for st in searchterms): running = False break return running def reloadService(self, service, **kwargs): """ Reload (HUP) a service so that it re-reads it's config files. Called by rules that are configuring a service to make the new configuration active. @param service: string; Name of service to be reloaded @return: reloaded @rtype: bool @author: ??? @change: Breen Malmberg - 04/10/2019 - method refactor; doc string edit; logging edit """ reloaded = True # force-reload: cause the configuration to be reloaded if the service supports this, # otherwise restart the service if it is running self.ch.executeCommand(self.svc + " " + service + " force-reload") retcode = self.ch.getReturnCode() if retcode != 0: reloaded = False self.logger.log(LogPriority.DEBUG, "Failed to reload service: " + service) return reloaded def listServices(self, **kwargs): """ Return a list containing strings that are service names. @return: service_list @rtype: list @author: ??? @change: Breen Malmberg - 04/10/2019 - method refactor; doc string edit; logging edit """ service_list = [] self.ch.executeCommand(self.chk + " --list") outputlines = self.ch.getOutput() for line in outputlines: try: service_list.append(line.split()[0]) except IndexError: pass return service_list def getStartCommand(self, service): ''' retrieve the start command. Mostly used by event recording @return: string - start command @author: dwalker ''' return self.svc + " " + service + " start" def getStopCommand(self, service): ''' retrieve the stop command. Mostly used by event recording @return: string - stop command @author: dwalker ''' return self.svc + " " + service + " stop" def getEnableCommand(self, service): ''' retrieve the enable command. Mostly used by event recording @return: string - enable command @author: dwalker ''' return self.chk + " " + service + " on" def getDisableCommand(self, service): ''' retrieve the start command. Mostly used by event recording @return: string - disable command @author: dwalker ''' return self.chk + " " + service + " off"
class lanlMacInfo(): ''' lanlMacInfo gets information from the mac and LDAP to help set basi computer data for the mac this includes: ComputerName HostName LocalHostname asset_id (property number) endUserName (owner) @author: ekkehard ''' def __init__(self, logger): ''' initialize lanlMacInfo @author: ekkehard ''' self.logdispatch = logger # Make sure we have the full path for all commands self.ch = CommandHelper(logger) self.LANLAssetTagNVRAM = "" self.LANLAssetTagFilesystem = "" self.macAddressDictionary = {} self.dictionary = {} self.accuracyDictionary = {} self.dictionaryItem = None self.keys = None self.key = None self.keyIndexNumber = 0 self.keysNumberOf = 0 self.entries = -1 self.computerName = "" self.computerNameDiskUtility = "" self.hostName = "" self.hostNameDiskUtility = "" self.localHostname = "" self.localHostnameDiskUtility = "" self.endUsername = "" self.assetTag = "" # Make sure we have the full path for all commands self.ns = "/usr/sbin/networksetup" self.scutil = "/usr/sbin/scutil" self.jamf = "/usr/sbin/jamf" self.nvram = "/usr/sbin/nvram" self.ldap = "/usr/bin/ldapsearch" self.lanl_property_file = "/Library/Preferences/lanl_property_number.txt" # Initialize accuracy modules self.updateAssetTagAccuracy(True, 0, "", True) self.updateEndUserNameAccuracy(True, 0, "", True) self.updateComputerNameAccuracy(True, 0, "", True) # reset messages and initialize everyting self.messageReset() self.initializeLanlAssetTagNVRAM() self.initializeLanlAssetTagFilesystem() self.initializeDiskUtilityInfo() self.populateFromMac() self.determinAccuracy() def gotoFirstItemLDAP(self): ''' go to the first entry in the LDAP dictionary @author: ekkehard @return: dictionary entry ''' self.keyIndexNumber = 0 self.keys = sorted(self.dictionary.keys()) self.keysNumberOf = len(self.keys) if self.keysNumberOf > self.keyIndexNumber: self.key = self.keys[self.keyIndexNumber] self.dictinaryItem = self.dictionary[self.key] else: self.key = None self.dictinaryItem = None return self.dictinaryItem def gotoNextItemLDAP(self): ''' go to the next entry in the LDAP dictionary @author: ekkehard @return: dictionary entry ''' self.keyIndexNumber = self.keyIndexNumber + 1 self.keys = sorted(self.dictionary.keys()) self.keysNumberOf = len(self.keys) if (self.keysNumberOf - 1) < self.keyIndexNumber: self.keyIndexNumber = 0 self.dictinaryItem = None else: self.key = self.keys[self.keyIndexNumber] self.dictinaryItem = self.dictionary[self.key] return self.dictinaryItem def getCurrentItemLDAP(self): ''' get the current item in the LDAP dictionary @author: ekkehard @return: dictionary entry ''' return self.dictinaryItem def getComputerInfoCompliance(self): ''' see if all is set correctly @author: ekkehard @return: boolean - True of False ''' success = True compliant = True # Check computername messagestring = "ComputerName Confidence level of " + \ str(self.getSuggestedComputerNameConfidenceOnly()) + "%" if not(self.getSuggestedComputerNameConfidenceOnly() == 100): compliant = False messagestring = messagestring + " is less than 100%" messagestring = messagestring + "; ComputerName (" + \ self.getDiskUtilityComputerName() + ") and proposed ComputerName (" + \ self.getSuggestedComputerName() + ")" if not(self.getDiskUtilityComputerName() == self.getSuggestedComputerName()): compliant = False messagestring = messagestring + " are not equal;" else: messagestring = messagestring + " are equal;" if not compliant: messagestring = "- Not compliant; " + messagestring if not(self.computerNameAccuracyLevelWhy == "" ): messagestring = messagestring + " - " + self.computerNameAccuracyLevelWhy + ";" success = False else: messagestring = "- compliant; " + messagestring self.messageAppend(messagestring) # Check hostname compliant = True messagestring = "HostName confidence level of " + \ str(self.getSuggestedComputerNameConfidenceOnly()) + "%" if not(self.getSuggestedComputerNameConfidenceOnly() == 100): compliant = False messagestring = messagestring + " is less than 100%" messagestring = messagestring + "; HostName (" + \ self.getDiskUtilityHostName() + ") and proposed HostName (" + \ self.getSuggestedHostName() + ")" if not(self.getDiskUtilityHostName() == self.getSuggestedHostName()): compliant = False messagestring = messagestring + " are not equal;" else: messagestring = messagestring + " are equal;" if not compliant: messagestring = "- Not compliant; " + messagestring if not(self.computerNameAccuracyLevelWhy == "" ): messagestring = messagestring + " - " + self.computerNameAccuracyLevelWhy + ";" success = False else: messagestring = "- compliant; " + messagestring self.messageAppend(messagestring) # Check localhostname compliant = True messagestring = "LocalHostName confidence level of " + \ str(self.getSuggestedComputerNameConfidenceOnly()) + "%" if not(self.getSuggestedComputerNameConfidenceOnly() == 100): compliant = False messagestring = messagestring + " is less than 100%" messagestring = messagestring + "; LocalHostName (" + \ self.getDiskUtilityLocalHostName() + ") and proposed LocalHostName (" + \ self.getSuggestedLocalHostName() + ")" if not(self.getDiskUtilityLocalHostName() == self.getSuggestedLocalHostName()): compliant = False messagestring = messagestring + " are not equal;" else: messagestring = messagestring + " are equal;" if not compliant: messagestring = "- Not compliant; " + messagestring if not(self.computerNameAccuracyLevelWhy == "" ): messagestring = messagestring + " - " + self.computerNameAccuracyLevelWhy + ";" success = False else: messagestring = "- compliant; " + messagestring self.messageAppend(messagestring) return success def getDiskUtilityComputerName(self): ''' get the ComputerName determined by disk utility @author: ekkehard @return: string ''' return self.computerNameDiskUtility def getDiskUtilityHostName(self): ''' get the HostName determined by disk utility @author: ekkehard @return: string ''' return self.hostNameDiskUtility def getDiskUtilityLocalHostName(self): ''' get the LocalHostName determined by disk utility @author: ekkehard @return: string ''' return self.localHostnameDiskUtility def getLANLAssetTagNVRAM(self): ''' get the asset_id set in NVRAM determined @author: ekkehard @return: string ''' return str(self.LANLAssetTagNVRAM) def getLANLAssetTagFilesystem(self): ''' get the asset_id set in file system @author: ekkehard @return: string ''' return str(self.LANLAssetTagFilesystem) def getSuggestedAssetTag(self): ''' get the suggested asset_id @author: ekkehard @return: string ''' return self.assetTag def getSuggestedAssetTagConfidence(self): ''' get the suggested asset_id and asset_id confidence level @author: ekkehard @return: string ''' displayValue = str(self.assetTag) + " (" + str(self.assetTagAccuracyLevel) + "%)" return displayValue def getSuggestedAssetTagConfidenceOnly(self): ''' get the suggested asset_id confidence level @author: ekkehard @return: real ''' return self.assetTagAccuracyLevel def getSuggestedComputerName(self): ''' get the suggested ComputerName @author: ekkehard @return: string ''' return self.computerName def getSuggestedComputerNameConfidence(self): ''' get the suggested ComputerName and ComputerName confidence level @author: ekkehard @return: string ''' displayValue = str(self.computerName) + " (" + str(self.computerNameAccuracyLevel) + "%)" return displayValue def getSuggestedComputerNameConfidenceOnly(self): ''' get the suggested ComputerName confidence level @author: ekkehard @return: real ''' return self.computerNameAccuracyLevel def getSuggestedHostName(self): ''' get the suggested HostName @author: ekkehard @return: string ''' return self.hostName def getSuggestedHostNameConfidence(self): ''' get the suggested HostName and HostName confidence level @author: ekkehard @return: string ''' displayValue = str(self.hostName) + " (" + str(self.computerNameAccuracyLevel) + "%)" return displayValue def getSuggestedHostNameConfidenceOnly(self): ''' get the suggested HostName confidence level @author: ekkehard @return: real ''' return self.computerNameAccuracyLevel def getSuggestedLocalHostName(self): ''' get the suggested LocalHostName @author: ekkehard @return: string ''' return self.localHostname def getSuggestedLocalHostNameConfidence(self): ''' get the suggested LocalHostName and LocalHostName confidence level @author: ekkehard @return: string ''' displayValue = str(self.localHostname) + " (" + str(self.computerNameAccuracyLevel) + "%)" return displayValue def getSuggestedLocalHostNameConfidenceOnly(self): ''' get the suggested LocalHostName confidence level @author: ekkehard @return: real ''' return self.computerNameAccuracyLevel def getSuggestedEndUsername(self): ''' get the suggested EndUserName or Owner @author: ekkehard @return: string ''' return self.endUsername def getSuggestedEndUsernameConfidence(self): ''' get the suggested EndUserName or Owner and EndUserName or Owner confidence level @author: ekkehard @return: string ''' displayValue = str(self.endUsername) + " (" + str(self.endUserNameAccuracyLevel) + "%)" return displayValue def getSuggestedEndUsernameConfidenceOnly(self): ''' get the suggested EndUserName or Owner confidence level @author: ekkehard @return: real ''' return self.endUserNameAccuracyLevel def setComputerInfo(self): ''' set the computer info on the computer @author: ekkehard @return: boolean - True ''' try: success = True updatesWhereMade = False output = [] computerName = self.getSuggestedComputerName() hostname = self.getSuggestedHostName() localHostName = self.getSuggestedLocalHostName() if self.computerNameAccuracyLevel == 100: if not(self.computerNameDiskUtility == computerName): command = [self.scutil,"--set", "ComputerName", computerName] self.ch.executeCommand(command) errorcode = self.ch.getError() output = self.ch.getOutput() updatesWhereMade = True messagestring = " - ComputerName set to " + computerName self.messageAppend(messagestring) else: messagestring = " - ComputerName was alreday " + computerName self.messageAppend(messagestring) if not(self.hostNameDiskUtility == hostname): command = [self.scutil,"--set", "HostName", hostname] self.ch.executeCommand(command) errorcode = self.ch.getError() output = self.ch.getOutput() updatesWhereMade = True messagestring = " - HostName set to " + hostname self.messageAppend(messagestring) else: messagestring = " - HostName was alreday " + hostname self.messageAppend(messagestring) if not(self.localHostnameDiskUtility == localHostName): command = [self.scutil,"--set", "LocalHostName", localHostName] errorcode = self.ch.getError() self.ch.executeCommand(command) output = self.ch.getOutput() updatesWhereMade = True messagestring = " - LocalHostName set to " + localHostName self.messageAppend(messagestring) else: messagestring = " - LocalHostName was alreday " + localHostName self.messageAppend(messagestring) except(KeyboardInterrupt, SystemExit): raise except Exception: messagestring = traceback.format_exc() self.logdispatch.log(LogPriority.ERROR, messagestring) if updatesWhereMade == True: self.initializeDiskUtilityInfo() return success def setJAMFInfo(self): ''' set the assetTag and endUserName via the jamf recon command @author: ekkehard @return: boolean - True ''' try: success = True assetTag = self.getSuggestedAssetTag() endUser = self.getSuggestedEndUsername() if self.assetTagAccuracyLevel == 100 and self.endUserNameAccuracyLevel == 100: command = [self.jamf, "recon", "-assetTag", assetTag, "-endUsername", endUser] self.ch.executeCommand(command) output = self.ch.getOutput() messagestring = " - JAMF assetTag set to " + assetTag + " and endUsername set to " + endUser self.messageAppend(messagestring) elif self.assetTagAccuracyLevel == 100: command = [self.jamf, "recon", "-assetTag", assetTag] self.ch.executeCommand(command) output = self.ch.getOutput() endUser = "" messagestring = " - JAMF assetTag set to " + assetTag self.messageAppend(messagestring) elif self.endUserNameAccuracyLevel == 100: command = [self.jamf, "recon", "-endUsername", endUser] self.ch.executeCommand(command) output = self.ch.getOutput() assetTag = "" messagestring = " - JAMF endUsername set to " + endUser self.messageAppend(messagestring) else: success = False messagestring = " - JAMF settings were not changed because confidence was only " + \ str(self.assetTagAccuracyLevel) + "%" self.messageAppend(messagestring) except(KeyboardInterrupt, SystemExit): raise except Exception: messagestring = traceback.format_exc() self.logdispatch.log(LogPriority.ERROR, messagestring) return success def setLANLAssetTagNVRAM(self): ''' set the assetTag and endUserName via the jamf recon command @author: ekkehard @return: boolean - True ''' try: assetTag = self.getSuggestedAssetTag() if self.assetTagAccuracyLevel == 100: if not(self.getLANLAssetTagNVRAM() == assetTag): command = [self.nvram, "asset_id=" + assetTag] self.ch.executeCommand(command) self.initializeLanlAssetTagNVRAM() messagestring = " - NVRAM asset_id set to " + assetTag self.messageAppend(messagestring) else: messagestring = " - NVRAM asset_id was already set to " + assetTag self.messageAppend(messagestring) else: assetTag = "" messagestring = " - NVRAM asset_id was not changed because confidence was only " + \ str(self.assetTagAccuracyLevel) + "%" self.messageAppend(messagestring) except(KeyboardInterrupt, SystemExit): raise except Exception: messagestring = traceback.format_exc() self.logdispatch.log(LogPriority.ERROR, messagestring) return assetTag def setLANLAssetTagFilesystem(self): ''' set the assetTag on the file system @author: ekkehard @return: boolean - True ''' try: assetTag = self.getSuggestedAssetTag() if self.assetTagAccuracyLevel == 100: if not(self.getLANLAssetTagFilesystem() == assetTag): try : filepointer = open(self.lanl_property_file, "w") filepointer.write(assetTag) filepointer.close() self.initializeLanlAssetTagFilesystem() assetTag = self.getLANLAssetTagFilesystem() except Exception, err : messagestring = "Problem writing: " + self.lanl_property_file + \ " error: " + str(err) self.logdispatch.log(LogPriority.DEBUG, messagestring) else:
class Yum(object): ''' The template class that provides a framework that must be implemented by all platform specific pkgmgr classes. @author: Derek T Walker @change: 2012/08/06 dwalker - Original Implementation @change: 2015/08/20 eball - Added getPackageFromFile ''' def __init__(self, logger): self.environ = Environment() self.logger = logger self.ch = CommandHelper(self.logger) self.yumloc = "/usr/bin/yum" self.install = self.yumloc + " install -y " self.remove = self.yumloc + " remove -y " self.search = self.yumloc + " list " self.checkupdates = self.search + "updates " self.listavail = self.search + "available " self.listinstalled = self.search + "installed " self.updatepkg = self.yumloc + " update -y --obsoletes " myos = self.environ.getostype().lower() if re.search("red hat.*?release 6", myos) or \ re.search("^centos$", myos.strip()): self.rpmloc = "/bin/rpm" else: self.rpmloc = "/usr/bin/rpm" self.provides = self.rpmloc + " -qf " self.query = self.rpmloc + " -qa " def installpackage(self, package): ''' Install a package. Return a bool indicating success or failure. @param package: string; Name of the package to be installed, must be recognizable to the underlying package manager. @return: installed @rtype: bool @author: Derek T. Walker @change: Breen Malmberg - 4/24/2017 - refactored method; added logging; replaced detailedresults with logging @change: Breen Malmberg - 10/1/2018 - added check for package manager lock and retry loop ''' installed = True maxtries = 12 trynum = 0 while psRunning("yum"): trynum += 1 if trynum == maxtries: self.logger.log(LogPriority.DEBUG, "Timed out while attempting to install package due to yum package manager being in-use by another process.") installed = False return installed else: self.logger.log(LogPriority.DEBUG, "Yum package manager is in-use by another process. Waiting for it to be freed...") time.sleep(5) try: try: self.ch.executeCommand(self.install + package) retcode = self.ch.getReturnCode() errstr = self.ch.getErrorString() if retcode != 0: raise repoError('yum', retcode) except repoError as repoerr: if not repoerr.success: self.logger.log(LogPriority.WARNING, str(repoerr)) installed = False if installed: self.logger.log(LogPriority.DEBUG, "Package " + str(package) + " was installed successfully") else: self.logger.log(LogPriority.DEBUG, "Failed to install package " + str(package)) except Exception: raise return installed def removepackage(self, package): ''' Remove a package. Return a bool indicating success or failure. @param package: string; Name of the package to be removed, must be recognizable to the underlying package manager. @return: removed @rtype: bool @author: Derek T. Walker @change: Breen Malmberg - 4/24/2017 - refactored method; added logging; replaced detailedresults with logging ''' removed = True maxtries = 12 trynum = 0 while psRunning("yum"): trynum += 1 if trynum == maxtries: self.logger.log(LogPriority.DEBUG, "Timed out while attempting to remove package, due to yum package manager being in-use by another process.") removed = False return removed else: self.logger.log(LogPriority.DEBUG, "Yum package manager is in-use by another process. Waiting for it to be freed...") time.sleep(5) try: try: self.ch.executeCommand(self.remove + package) retcode = self.ch.getReturnCode() errstr = self.ch.getErrorString() if retcode != 0: raise repoError('yum', retcode) except repoError as repoerr: if not repoerr.success: self.logger.log(LogPriority.WARNING, str(repoerr)) removed = False if removed: self.logger.log(LogPriority.DEBUG, "Package " + str(package) + " was successfully removed") else: self.logger.log(LogPriority.DEBUG, "Failed to remove package " + str(package)) except Exception: raise return removed def checkInstall(self, package): ''' Check the installation status of a package. Return a bool; True if the package is installed. @param package: string; Name of the package whose installation status is to be checked, must be recognizable to the underlying package manager. @return: found @rtype: bool @author: Derek T. Walker @change: Breen Malmberg - 4/24/2017 - refactored method; added logging; replaced detailedresults with logging ''' installed = True errstr = "" maxtries = 12 trynum = 0 while psRunning("yum"): trynum += 1 if trynum == maxtries: self.logger.log(LogPriority.DEBUG, "Timed out while attempting to check status of package, due to yum package manager being in-use by another process.") installed = False return installed else: self.logger.log(LogPriority.DEBUG, "Yum package manager is in-use by another process. Waiting for it to be freed...") time.sleep(5) try: try: self.ch.executeCommand(self.listinstalled + package) retcode = self.ch.getReturnCode() errstr = self.ch.getErrorString() if retcode != 0: raise repoError('yum', retcode, str(errstr)) except repoError as repoerr: if not repoerr.success: self.logger.log(LogPriority.WARNING, str(repoerr)) installed = False if installed: self.logger.log(LogPriority.DEBUG, "Package " + str(package) + " is installed") else: self.logger.log(LogPriority.DEBUG, "Package " + str(package) + " is NOT installed") except Exception: raise return installed def Update(self, package=""): ''' update specified package if any updates are available for it if no package is specified, update all packages which can be updated on the system @param package: string; name of package to update @return: updated @rtype: bool @author: Breen Malmberg ''' updated = True try: try: self.ch.executeCommand(self.updatepkg + package) retcode = self.ch.getReturnCode() errstr = self.ch.getErrorString() if retcode != 0: raise repoError('yum', retcode, str(errstr)) except repoError as repoerr: if not repoerr.success: self.logger.log(LogPriority.WARNING, str(errstr)) updated = False if package: if updated: self.logger.log(LogPriority.DEBUG, "Package " + str(package) + " was successfully updated") else: self.logger.log(LogPriority.DEBUG, "No updates were found for package " + str(package)) else: if updated: self.logger.log(LogPriority.DEBUG, "All packages were successfully updated") else: self.logger.log(LogPriority.DEBUG, "No updates were found for this system") except Exception: raise return updated def checkUpdate(self, package=""): ''' check if there are any updates available for specified package if no package is specified, check if any updates are available for the current system @param package: string; name of package to check @return: updatesavail @rtype: bool @author: Breen Malmberg ''' updatesavail = False try: try: self.ch.executeCommand(self.checkupdates + package) retcode = self.ch.getReturnCode() output = self.ch.getOutputString() errstr = self.ch.getErrorString() if retcode != 0: raise repoError('yum', retcode, str(errstr)) else: if re.search("Updated packages", output, re.IGNORECASE): updatesavail = True except repoError as repoerr: if not repoerr.success: self.logger.log(LogPriority.WARNING, str(errstr)) else: if re.search("Updated packages", output, re.IGNORECASE): updatesavail = True if package: if updatesavail: self.logger.log(LogPriority.DEBUG, "Updates are available for package " + str(package)) else: self.logger.log(LogPriority.DEBUG, "No updates are available for package " + str(package)) else: if updatesavail: self.logger.log(LogPriority.DEBUG, "Updates are available for this system") else: self.logger.log(LogPriority.DEBUG, "No updates are available for this system") except Exception: raise return updatesavail def checkAvailable(self, package): ''' check if specified package is available to install return True if it is return False if not @param package: string; name of package to check @return: available @rtype: bool @author: Breen Malmberg ''' available = True maxtries = 12 trynum = 0 while psRunning("yum"): trynum += 1 if trynum == maxtries: self.logger.log(LogPriority.DEBUG, "Timed out while attempting to check availability of package, due to yum package manager being in-use by another process.") available = False return available else: self.logger.log(LogPriority.DEBUG, "Yum package manager is in-use by another process. Waiting for it to be freed...") time.sleep(5) try: try: self.ch.executeCommand(self.listavail + package) retcode = self.ch.getReturnCode() errstr = self.ch.getErrorString() if retcode != 0: raise repoError('yum', retcode, str(errstr)) except repoError as repoerr: if not repoerr.success: self.logger.log(LogPriority.DEBUG, str(repoerr)) available = False if available: self.logger.log(LogPriority.DEBUG, "Package " + str(package) + " is available to install") else: self.logger.log(LogPriority.DEBUG, "No package " + str(package) + " was found to install") except Exception: raise return available def getPackageFromFile(self, filename): ''' Returns the name of the package that provides the given filename/path. @param filename: string; The name or path of the file to resolve @return: packagename @rtype: string @author: Eric Ball @change: Breen Malmberg - 4/24/2017 - refactored method; added logging; replaced detailedresults with logging ''' packagename = "" try: try: self.ch.executeCommand(self.provides + filename) retcode = self.ch.getReturnCode() outputstr = self.ch.getOutputString() errstr = self.ch.getErrorString() if retcode != 0: raise repoError('yum', retcode, str(errstr)) else: packagename = outputstr except repoError as repoerr: if not repoerr.success: self.logger.log(LogPriority.WARNING, str(errstr)) except Exception: raise return packagename def getInstall(self): return self.install def getRemove(self): return self.remove
class Freebsd(object): '''The template class that provides a framework that must be implemented by all platform specific pkgmgr classes. :version: :author:Derek T Walker 08-06-2012''' def __init__(self,logger): self.logger = logger self.detailedresults = "" self.ch = CommandHelper(self.logger) self.install = "/usr/sbin/pkg_add -r -f " self.remove = "/usr/sbin/pkg_delete " ############################################################################### def installpackage(self, package): ''' Install a package. Return a bool indicating success or failure. @param string package : Name of the package to be installed, must be recognizable to the underlying package manager. @return bool : @author''' try: installed = False # retval = call(self.install + package,stdout=None,shell=True) self.ch.executeCommand(self.install + package) if self.ch.getReturnCode() == 0: # if retval == 0: self.detailedresults += package + " pkg installed successfully" installed = True else: self.detailedresults += package + " pkg not able to install" self.logger.log(LogPriority.INFO, self.detailedresults) return installed except(KeyboardInterrupt,SystemExit): raise except Exception: self.detailedresults += traceback.format_exc() self.logger.log(LogPriority.INFO, self.detailedresults) ############################################################################### def removepackage(self, package): ''' Remove a package. Return a bool indicating success or failure. @param string package : Name of the package to be removed, must be recognizable to the underlying package manager. @return : bool @author''' try: self.detailedresults = "" removed = False stringToMatch = package + "(.*)" self.ch.executeCommand(["/usr/sbin/pkg_info"]) output = self.ch.getOutput() # temp = Popen(["/usr/sbin/pkg_info"],stdout=PIPE,shell=True) # details = temp.stdout.readlines() # temp.stdout.close() for cell in output: cell2 = cell.split(" ") if re.search(stringToMatch,cell2[0]): retval = call(self.remove + cell2[0],stdout=None,shell=True) if retval == 0: self.detailedresults += package + " pkg removed \ successfully" removed = True else: self.detailedresults += package + " pkg not able\ to be removed" if not self.detailedresults: self.detailedresults += package + " pkg not found to remove" self.logger.log(LogPriority.INFO, self.detailedresults) return removed except(KeyboardInterrupt,SystemExit): raise except Exception: self.detailedresults += traceback.format_exc() self.logger.log(LogPriority.INFO, self.detailedresults) ############################################################################### def checkInstall(self, package): '''Check the installation status of a package. Return a bool; True if the package is installed. @param string package : Name of the package whose installation status is to be checked, must be recognizable to the underlying package manager. @return : bool @author''' try: self.detailedresults = "" present = False stringToMatch = package +"(.*)" self.ch.executeCommand(["/usr/sbin/pkg_info"]) output = self.ch.getOutput() # temp = Popen(["/usr/sbin/pkg_info"],stdout=PIPE,shell=False) # info = temp.stdout.readlines() # temp.stdout.close() for cell in output: cell2 = cell.split(" ") if re.search(stringToMatch,cell2[0]): self.detailedresults += package + " pkg found" present = True if not self.detailedresults: self.detailedresults += package + " pkg not found" self.logger.log(LogPriority.INFO, self.detailedresults) return present except(KeyboardInterrupt,SystemExit): raise except Exception: self.detailedresults += traceback.format_exc() self.logger.log(LogPriority.INFO, self.detailedresults) ############################################################################### def getInstall(self): return self.install ############################################################################### def getRemove(self): return self.remove
class Yum(object): '''The template class that provides a framework that must be implemented by all platform specific pkgmgr classes. :version: :author:Derek T Walker 08-06-2012''' def __init__(self,logger): self.logger = logger self.detailedresults = "" self.ch = CommandHelper(self.logger) self.install = "/usr/bin/yum install -y " self.remove = "/usr/bin/yum remove -y " self.search = "/usr/bin/yum search " self.rpm = "/bin/rpm -q " ############################################################################### def installpackage(self, package): '''Install a package. Return a bool indicating success or failure. @param string package : Name of the package to be installed, must be recognizable to the underlying package manager. @return bool : @author''' try: installed = False self.ch.executeCommand(self.install + package) output = self.ch.getOutputString() if self.ch.getReturnCode() == 0: installed = True self.detailedresults = package + " pkg installed successfully\n" else: self.detailedresults = package + " pkg not able to install\n" self.logger.log(LogPriority.DEBUG,self.detailedresults) return installed except(KeyboardInterrupt,SystemExit): raise except Exception: self.detailedresults = traceback.format_exc() self.logger.log(LogPriority.ERROR, self.detailedresults) raise(self.detailedresults) ############################################################################### def removepackage(self, package): '''Remove a package. Return a bool indicating success or failure. @param string package : Name of the package to be removed, must be recognizable to the underlying package manager. @return bool : @author''' method = "yum.remove" try: removed = False self.ch.executeCommand(self.remove + package) if self.ch.getReturnCode() == 0: removed = True self.detailedresults += package + " pkg removed successfully\n" else: self.detailedresults += package + " pkg not able to be removed\n" self.logger.log(LogPriority.DEBUG,[method,self.detailedresults]) return removed except(KeyboardInterrupt,SystemExit): raise except Exception: self.detailedresults = traceback.format_exc() self.logger.log(LogPriority.ERROR,[method,self.detailedresults]) raise(self.detailedresults) ############################################################################### def checkInstall(self, package): '''Check the installation status of a package. Return a bool; True if the package is installed. @param string package : Name of the package whose installation status is to be checked, must be recognizable to the underlying package manager. @return bool : @author''' try: found = False self.ch.executeCommand(self.rpm + package) output = self.ch.getOutputString() #for redhat systems only if self.ch.getReturnCode() == 0: found = True self.detailedresults += package + " pkg found\n" else: self.detailedresults += package + " pkg not found\n" self.logger.log(LogPriority.DEBUG, self.detailedresults) return found except(KeyboardInterrupt,SystemExit): raise except Exception: self.detailedresults = traceback.format_exc() self.logger.log(LogPriority.ERROR, self.detailedresults) raise(self.detailedresults) ############################################################################### def checkAvailable(self,package): try: found = False self.ch.executeCommand(self.search + package) output = self.ch.getOutputString() if re.search("no matches found", output.lower()): self.detailedresults += package + " pkg is not available " + \ " or may be misspelled\n" elif re.search("matched", output.lower()): self.detailedresults += package + " pkg is available\n" found = True self.logger.log(LogPriority.DEBUG, self.detailedresults) return found except(KeyboardInterrupt,SystemExit): raise except Exception: self.detailedresults = traceback.format_exc() self.logger.log(LogPriority.ERROR, self.detailedresults) raise(self.detailedresults) ############################################################################### def getInstall(self): return self.install ############################################################################### def getRemove(self): return self.remove
class AptGet(object): ''' Linux specific package manager for distributions that use the apt-get command to install packages. @author: Derek T Walker @change: 2012/08/06 Derek Walker - Original Implementation @change: 2015/08/20 eball - Added getPackageFromFile @change: 2017/04/27 Breen Malmberg - added two methods checkUpdate and Update; fixed doc string formatting; removed detailedresults reset in init; replaced with --force-yes flag with --assume-yes (from the man page for apt-get: Force yes. This is a dangerous option that will cause apt-get to continue without prompting if it is doing something potentially harmful. It should not be used except in very special situations. Using --force-yes can potentially destroy your system!) @change: 2017/08/16 bgonz12 - Added DEBIAN_FRONTEND=noninteractive env var to remove function @change: 2017/10/18 Breen Malmberg - changed class var names to be more self-explanatory; changed command to check whether there are available packages to use the canonical debian/ubuntu method; added calls to repoError exception to determine exact nature and cause of any errors with querying or calling repositories on the system (this adds logging of the nature and cause(s) as well); changed log messaging to be more consistent in style/format; removed calls to validateParam due to concerns about the stability and reliability of that method ''' def __init__(self, logger): self.logger = logger self.ch = CommandHelper(self.logger) self.aptgetloc = "/usr/bin/apt-get" self.aptcacheloc = "/usr/bin/apt-cache" self.dpkgloc = "/usr/bin/dpkg" self.aptinstall = "DEBIAN_FRONTEND=noninteractive " + self.aptgetloc + " -y --assume-yes install " self.aptremove = "DEBIAN_FRONTEND=noninteractive " + self.aptgetloc + " -y remove " self.dpkgsearch = self.dpkgloc + " -S " self.dpkgchkinstalled = self.dpkgloc + " -l " self.aptchkupdates = self.aptgetloc + " -u upgrade --assume-no " self.aptupgrade = self.aptgetloc + " -u upgrade --assume-yes " self.aptchkavail = self.aptcacheloc + " policy " def installpackage(self, package): ''' Install a package. Return a bool indicating success or failure. @param package: string; Name of the package to be installed, must be recognizable to the underlying package manager. @return: installed @rtype: bool @author: Derek Walker @change: Breen Malmberg - 4/27/2017 - fixed doc string formatting; method now returns a variable; parameter validation added detailedresults replaced with logging @change: Breen Malmberg - 10/1/2018 - added check for package manager lock and retry loop ''' installed = True maxtries = 12 trynum = 0 pslist = ["apt", "apt-get", "dpkg"] for ps in pslist: while psRunning(ps): trynum += 1 if trynum == maxtries: self.logger.log(LogPriority.DEBUG, "Timed out while attempting to install package, due to Apt package manager being in-use by another process.") installed = False return installed else: self.logger.log(LogPriority.DEBUG, "Apt package manager is in-use by another process. Waiting for it to be freed...") time.sleep(5) try: try: self.ch.executeCommand(self.aptinstall + package) retcode = self.ch.getReturnCode() errstr = self.ch.getErrorString() if retcode != 0: raise repoError('apt', retcode) except repoError as repoerr: if not repoerr.success: installed = False self.logger.log(LogPriority.WARNING, str(errstr)) if installed: self.logger.log(LogPriority.DEBUG, "Successfully installed package " + str(package)) else: self.logger.log(LogPriority.DEBUG, "Failed to install package " + str(package)) except Exception: raise return installed def removepackage(self, package): ''' Remove a package. Return a bool indicating success or failure. @param package: string; Name of the package to be removed, must be recognizable to the underlying package manager. @return: removed @rtype: bool @author: Derek T. Walker ''' removed = True maxtries = 12 trynum = 0 pslist = ["apt", "apt-get", "dpkg"] for ps in pslist: while psRunning(ps): trynum += 1 if trynum == maxtries: self.logger.log(LogPriority.DEBUG, "Timed out while attempting to remove package, due to Apt package manager being in-use by another process.") removed = False return removed else: self.logger.log(LogPriority.DEBUG, "Apt package manager is in-use by another process. Waiting for it to be freed...") time.sleep(5) try: try: self.ch.executeCommand(self.aptremove + package) retcode = self.ch.getReturnCode() errstr = self.ch.getErrorString() if retcode != 0: raise repoError('apt', retcode) except repoError as repoerr: if not repoerr.success: removed = False self.logger.log(LogPriority.WARNING, str(errstr)) if removed: self.logger.log(LogPriority.DEBUG, "Successfully removed package " + str(package)) else: self.logger.log(LogPriority.DEBUG, "Failed to remove package " + str(package)) except Exception: raise return removed def checkInstall(self, package): ''' Check the installation status of a package. Return a bool; True if the package is installed. @param: package: string; Name of the package whose installation status is to be checked, must be recognizable to the underlying package manager. @return: installed @rtype: bool @author: Derek Walker @change: Breen Malmberg - 4/27/2017 - fixed doc string formatting; method now returns a variable; replaced detailedresults with logging ''' installed = False stringToMatch = "ii\s+" + str(package) outputstr = "" maxtries = 12 trynum = 0 pslist = ["apt", "apt-get", "dpkg"] for ps in pslist: while psRunning(ps): trynum += 1 if trynum == maxtries: self.logger.log(LogPriority.DEBUG, "Timed out while attempting to check status of package, due to Apt package manager being in-use by another process.") installed = False return installed else: self.logger.log(LogPriority.DEBUG, "Apt package manager is in-use by another process. Waiting for it to be freed...") time.sleep(5) try: try: self.ch.executeCommand(self.dpkgchkinstalled + package) retcode = self.ch.getReturnCode() outputstr = self.ch.getOutputString() errstr = self.ch.getErrorString() if retcode != 0: raise repoError('apt', retcode, str(errstr)) except repoError as repoerr: if not repoerr.success: self.logger.log(LogPriority.WARNING, str(repoerr)) return False if re.search(stringToMatch, outputstr, re.IGNORECASE): installed = True if not installed: self.logger.log(LogPriority.DEBUG, "Package " + str(package) + " is NOT installed") else: self.logger.log(LogPriority.DEBUG, "Package " + str(package) + " is installed") except Exception: raise return installed def checkAvailable(self, package): ''' check if a given package is available @param package: string; Name of package to check @return: found @rtype: bool @author: Derek T. Walker @change: Breen Malmberg - 4/27/2017 - created doc string; pulled result logging out of conditional ''' found = False repoerr = "" outputstr = "" maxtries = 12 trynum = 0 pslist = ["apt", "apt-get", "dpkg"] for ps in pslist: while psRunning(ps): trynum += 1 if trynum == maxtries: self.logger.log(LogPriority.DEBUG, "Timed out while attempting to check availability of package, due to apt package manager being in-use by another process.") available = False return available else: self.logger.log(LogPriority.DEBUG, "apt package manager is in-use by another process. Waiting for it to be freed...") time.sleep(5) try: try: self.ch.executeCommand(self.aptchkavail + package) retcode = self.ch.getReturnCode() outputstr = self.ch.getOutputString() errstr = self.ch.getErrorString() if retcode != 0: raise repoError('apt', retcode, str(errstr)) except repoError as repoerr: if not repoerr.success: self.logger.log(LogPriority.WARNING, str(repoerr)) return False if re.search(package, outputstr, re.IGNORECASE): found = True if found: self.logger.log(LogPriority.DEBUG, "Package " + str(package) + " is available to install") else: self.logger.log(LogPriority.DEBUG, "Package " + str(package) + " is NOT available to install") except Exception: raise return found def Update(self, package=""): ''' update the specified package if any updates are available for it if no package is specified, apply all available updates for the system @param package: string; (OPTIONAL) name of package to update @return: updated @rtype: bool @author: Breen Malmberg ''' updated = True try: try: self.ch.executeCommand(self.aptupgrade + package) retcode = self.ch.getReturnCode() errstr = self.ch.getErrorString() if retcode != 0: raise repoError('apt', retcode, str(errstr)) except repoError as repoerr: if not repoerr.success: self.logger.log(LogPriority.WARNING, str(errstr)) updated = False if package: if updated: self.logger.log(LogPriority.DEBUG, "Package " + str(package) + " was updated successfully") else: self.logger.log(LogPriority.DEBUG, "Failed to apply updates to package " + str(package)) else: if updated: self.logger.log(LogPriority.DEBUG, "All updates were installed successfully") else: self.logger.log(LogPriority.DEBUG, "Failed to apply updates") except Exception: raise return updated def checkUpdate(self, package=""): ''' check for updates for specified package if no package is specified, then check for updates for the entire system @param package: string; (OPTIONAL) Name of package to check @return: updatesavail @rtype: bool @author: Breen Malmberg ''' updatesavail = False try: try: self.ch.executeCommand(self.aptchkupdates + package) retcode = self.ch.getReturnCode() errstr = self.ch.getErrorString() if retcode != 0: raise repoError('apt', retcode, str(errstr)) except repoError as repoerr: if not repoerr.success: self.logger.log(LogPriority.WARNING, str(errstr)) return False else: updatesavail = True if package: if updatesavail: self.logger.log(LogPriority.DEBUG, "Updates are available for package " + str(package)) else: self.logger.log(LogPriority.DEBUG, "No updates are available for package " + str(package)) else: if updatesavail: self.logger.log(LogPriority.DEBUG, "Updates are available for this system") else: self.logger.log(LogPriority.DEBUG, "No updates are available for this system") except Exception: raise return updatesavail def getPackageFromFile(self, filename): ''' Returns the name of the package that provides the given filename/path. @param: filename: string; The name or path of the file to resolve @return: packagename @rtype: string @author: Eric Ball @change: Breen Malmberg - 4/17/2017 - fixed doc string formatting; method now returns a variable; added param validation ''' packagename = "" try: try: self.ch.executeCommand(self.dpkgsearch + filename) retcode = self.ch.getReturnCode() errstr = self.ch.getErrorString() if retcode != 0: raise repoError('apt', retcode, str(errstr)) if self.ch.getReturnCode() == 0: output = self.ch.getOutputString() packagename = output.split(":")[0] except repoError as repoerr: if not repoerr.success: self.logger.log(LogPriority.WARNING, str(errstr)) pass except Exception: raise return packagename def getInstall(self): return self.aptinstall def getRemove(self): return self.aptremove
class AptGet(object): """Linux specific package manager for distributions that use the apt-get command to install packages. @author: Derek T Walker @change: 2012/08/06 dwalker - Original Implementation @change: 2015/08/20 eball - Added getPackageFromFile """ def __init__(self, logger): self.logger = logger self.detailedresults = "" self.ch = CommandHelper(self.logger) self.install = "sudo DEBIAN_FRONTEND=noninteractive /usr/bin/apt-get -y --force-yes install " self.remove = "/usr/bin/apt-get -y remove " ############################################################################### def installpackage(self, package): """Install a package. Return a bool indicating success or failure. @param string package : Name of the package to be installed, must be recognizable to the underlying package manager. @return bool : @author dwalker""" try: self.ch.executeCommand(self.install + package) if self.ch.getReturnCode() == 0: self.detailedresults = package + " pkg installed successfully" self.logger.log(LogPriority.DEBUG, self.detailedresults) return True else: # try to install for a second time self.ch.executeCommand(self.install + package) if self.ch.getReturnCode() == 0: self.detailedresults = package + " pkg installed successfully" self.logger.log(LogPriority.DEBUG, self.detailedresults) return True else: self.detailedresults = package + " pkg not able to install" self.logger.log(LogPriority.DEBUG, self.detailedresults) return False except (KeyboardInterrupt, SystemExit): raise except Exception: self.detailedresults = traceback.format_exc() self.logger.log(LogPriority.ERROR, self.detailedresults) raise (self.detailedresults) ############################################################################### def removepackage(self, package): """Remove a package. Return a bool indicating success or failure. @param string package : Name of the package to be removed, must be recognizable to the underlying package manager. @return bool : @author""" try: self.ch.executeCommand(self.remove + package) if self.ch.getReturnCode() == 0: self.detailedresults = package + " pkg removed successfully" self.logger.log(LogPriority.INFO, self.detailedresults) return True else: self.detailedresults = package + " pkg not able to be removed" self.logger.log(LogPriority.INFO, self.detailedresults) return False except (KeyboardInterrupt, SystemExit): raise except Exception: self.detailedresults = traceback.format_exc() self.logger.log(LogPriority.ERROR, self.detailedresults) raise (self.detailedresults) ############################################################################### def checkInstall(self, package): """Check the installation status of a package. Return a bool; True if the package is installed. @param: string package : Name of the package whose installation status is to be checked, must be recognizable to the underlying package manager. @return: bool : @author: dwalker""" try: stringToMatch = "(.*)" + package + "(.*)" self.ch.executeCommand(["/usr/bin/dpkg", "-l", package]) info = self.ch.getOutput() match = False for line in info: if search(stringToMatch, line): parts = line.split() if parts[0] == "ii": match = True break else: continue if match: self.detailedresults = package + " pkg found and installed\n" self.logger.log(LogPriority.INFO, self.detailedresults) return True else: self.detailedresults = package + " pkg not installed\n" self.logger.log(LogPriority.INFO, self.detailedresults) return False except (KeyboardInterrupt, SystemExit): raise except Exception: self.detailedresults = traceback.format_exc() self.logger.log(LogPriority.ERROR, self.detailedresults) raise (self.detailedresults) ############################################################################### def checkAvailable(self, package): try: found = False retval = call(["/usr/bin/apt-cache", "search", package], stdout=PIPE, stderr=PIPE, shell=False) if retval == 0: message = Popen(["/usr/bin/apt-cache", "search", package], stdout=PIPE, stderr=PIPE, shell=False) info = message.stdout.readlines() while message.poll() is None: continue message.stdout.close() for line in info: if search(package, line): found = True if found: self.detailedresults = package + " pkg is available" else: self.detailedresults = package + " pkg is not available" else: self.detailedresults = ( package + " pkg not found or may be \ misspelled" ) self.logger.log(LogPriority.DEBUG, self.detailedresults) return found except (KeyboardInterrupt, SystemExit): raise except Exception: self.detailedresults = traceback.format_exc() self.logger.log(LogPriority.ERROR, self.detailedresults) raise ############################################################################### def getPackageFromFile(self, filename): """Returns the name of the package that provides the given filename/path. @param: string filename : The name or path of the file to resolve @return: string name of package if found, None otherwise @author: Eric Ball """ try: self.ch.executeCommand("dpkg -S " + filename) if self.ch.getReturnCode() == 0: output = self.ch.getOutputString() pkgname = output.split(":")[0] return pkgname else: return None except (KeyboardInterrupt, SystemExit): raise except Exception: self.detailedresults = traceback.format_exc() self.logger.log(LogPriority.ERROR, self.detailedresults) raise (self.detailedresults) ############################################################################### def getInstall(self): return self.install ############################################################################### def getRemove(self): return self.remove