def validate_options(self, optionDict):
        users = ' '.join(tcs_utils.splitNaturally(optionDict['allowUsers']))
        groups = ' '.join(tcs_utils.splitNaturally(optionDict['allowGroups']))

        if users:
            self.settings.append(['AllowUsers', users, self._isEqualTo])
        if groups:
            self.settings.append(['AllowGroups', groups, self._isEqualTo])
Example #2
0
    def validate_input(self, optionDict=None):
        """
        Validate optionDict has required args, within acceptable ranges
        """

        self.__pass_min = self.validate_argument('passwordAgingMindays',
                                                 optionDict)
        self.__pass_max = self.validate_argument('passwordAgingMaxdays',
                                                 optionDict)
        self.__pass_warn = self.validate_argument('passwordAgingExpireWarning',
                                                  optionDict)
        self.__pass_inact = self.validate_argument('passwordAgingInvalidate',
                                                   optionDict)

        if optionDict['exemptSystemAccounts'] == '1':
            self.__exemptSystemAccounts = sb_utils.acctmgt.users.local_SystemUsers(
            )
        else:
            self.__exemptSystemAccounts = []

        self.__exemptSpecificAccounts = tcs_utils.splitNaturally(
            optionDict['exemptSpecificAccounts'])

        flag = 0
        if self.__pass_min < 1 or self.__pass_max < 1 or \
               self.__pass_inact < 0 or self.__pass_warn < 1:
            flag = 1

        if self.__pass_max < self.__pass_min:
            flag = 1

        if flag == 1:
            msg = 'Invalid option arg provided'
            self.logger.error(self.module_name, 'Scan Error: ' + msg)
            raise tcs_utils.ScanError('%s %s' % (self.module_name, msg))
Example #3
0
 def check_ownership(self, pathname, statinfo, attribs):
     msg = ""
     change_rec = {}    
     skip = False
     what_changed = []
     instead_of = []
     
     ifCurrentUname = None
     ifCurrentUID = None
     allowedUnames = []
     allowedUIDs = []
     
     ifCurrentGname = None
     ifCurrentGID = None
     allowedGnames = []
     allowedGIDs = []
     
     if os.path.islink(pathname):
         link_preface = "Link chasing -> "
     else:
         link_preface = ""
         
     #extract pieces
     try:
         if 'owner' in attribs:
             userList = attribs['owner']
             if type(userList) == type(1):
                 userList = "%d" % userList
             userList = tcs_utils.splitNaturally(userList, wordAdditions="<>*-_", whitespaceAdditions=",", uniq=True)
             try:
                 idx = userList.index('<SYSTEM>')
                 userList = userList [0:idx] + sb_utils.acctmgt.users.local_SystemUsers() + userList[idx+1:]
                 userList = tcs_utils.splitNaturally(userList, wordAdditions="<>*-_", whitespaceAdditions=",", uniq=True)
             except ValueError, e:
                 pass
             
             for entry in userList:
                 try:
                     allowedUIDs.append(self._map_uid_uname(entry)['uid'])
                     allowedUnames.append(entry)
                 except KeyError,e:
                     msg = "allowed username '%s' not found in local user list - ignoring" % entry
                     self.logger.warn('sb_utils.file.fileperms.check_ownership',msg)
             # ok, user was given, do we *have* any acceptable entries?  If not punt without doing anything
             if not allowedUnames:
                 msg = "No valid unames found for acceptable file ownership - skipping %s" % pathname
                 raise tcs_utils.ActionError(msg)
Example #4
0
 def checkGnames(self,passedGnames):
     self._allowed_gnames = []
     for gname in tcs_utils.splitNaturally(passedGnames):
         try:
             grp.getgrnam(gname)
             self._allowed_gnames.append(gname)
         except KeyError,e:
             msg = "Group '%s' doesn't exist, not including on allowed list" % gname
Example #5
0
 def checkUnames(self, passedUnames):
     self._allowed_unames = []
     for uname in tcs_utils.splitNaturally(passedUnames):
         try:
             pwd.getpwnam(uname)
             self._allowed_unames.append(uname)
         except KeyError,e:
             msg = "User '%s' doesn't exist, not including on allowed list" % uname
Example #6
0
 def get_shells(self):
     # Read /etc/shells
     try:
         shells = tcs_utils.splitNaturally(open(self.__shells).read(),
                                           wordAdditions="/-_")
     except Exception, err:
         msg = "Unable to read '/etc/shells' - may need to use 'Allowed Shells in /etc/shells' Module - %s" % str(
             err)
         self.logger.notice(self.module_name, 'Scan Failed: ' + msg)
         raise tcs_utils.ManualActionReqd('%s %s' % (self.module_name, msg))
Example #7
0
 def addShadow(self, nameList, listType):
     names = tcs_utils.splitNaturally(nameList,
                                      wordAdditions="<>*-_",
                                      whitespaceAdditions=",",
                                      uniq=True)
     if 'shadow' not in names:
         names.append('shadow')
         nameList = ' '.join(names)
         msg = "SUSE/openSUSE OS detected, adding 'shadow' to the approved %s users" % listType
         self.logger.notice(self.module_name, msg)
     return nameList
Example #8
0
    def validate_input(self, optionDict):
        trueFalse = {'1': True, 'True': True, '0': False, 'False': False}

        try:
            self.rpmsToIgnore = set(
                tcs_utils.splitNaturally(optionDict['packageExemptions'],
                                         wordAdditions='-.'))
            self.filesToIgnore = optionDict['fileExemptions'].splitlines()
            self.ignoreRootRoot000 = trueFalse[optionDict['honorChangesBySB']]
        except ValueError:
            msg = "Invalid option value -> '%s'" % optionDict
            raise tcs_utils.ScanError('%s %s' % (self.module_name, msg))
Example #9
0
    def validate_input(self, optionDict):
        """
        Validate option which must be min, max, warn, inactive
        in an array (i.e., [7,90,7,1])
        """

        # RMS - solaris locks account on expiration - not allowing a grace period of inactivity like linux
        #     - so we're 'creating' our own grace period by adding INACT to MAX, and
        #     - use this value for pass_inact

        self.__pass_min = self.validate_argument('passwordAgingMindays',
                                                 optionDict)
        self.__pass_max = self.validate_argument('passwordAgingMaxdays',
                                                 optionDict)
        self.__pass_warn = self.validate_argument('passwordAgingExpireWarning',
                                                  optionDict)
        self.__pass_inact = self.validate_argument(
            'passwordAgingInvalidate', optionDict) + self.__pass_max

        if optionDict['exemptSystemAccounts'] == '1':
            self.__exemptSystemAccounts = sb_utils.acctmgt.users.local_SystemUsers(
            )
        else:
            self.__exemptSystemAccounts = []

        self.__exemptSpecificAccounts = tcs_utils.splitNaturally(
            optionDict['exemptSpecificAccounts'])

        flag = 0
        if self.__pass_min < 1 or self.__pass_max < 1 or \
               self.__pass_inact < 0 or self.__pass_warn < 1:
            flag = 1

        if self.__pass_max < self.__pass_min:
            flag = 1

        if flag == 1:
            msg = 'Invalid option arg provided'
            self.logger.error(self.module_name, 'Scan Error: ' + msg)
            raise tcs_utils.ScanError('%s %s' % (self.module_name, msg))
Example #10
0
    def checkContent(self, action, fileName, requiredChanges):
        messages = []
        changes = {fileName: {}}

        sb_utils.file.exclusion.exlist()

        # if 'content' is empty, then skip checking the actual file contents and move on to permissions
        linesLeft = []
        linesMissing = []

        if requiredChanges['content']:
            currentLines = []
            try:
                currentLines = open(fileName, 'r').read().splitlines()
            except Exception, err:
                msg = "Unable to open file for analysis (%s)." % str(err)
                self.logger.error(self.module_name, 'Scan Error: ' + msg)
                raise tcs_utils.ScanError('%s %s' % (self.module_name, msg))

            contents = ' '.join(requiredChanges['content'].splitlines())
            lexer = shlex.shlex(contents)
            lexer.whitespace += ","
            allowedShells = tcs_utils.splitNaturally(
                requiredChanges['content'], wordAdditions="/-_")
            requiredSet = set(allowedShells)
            currentSet = set(currentLines)
            # if we have anything in currentFile after removing allowedLines, then we've got a problem

            linesLeft = currentSet - requiredSet
            linesMissing = requiredSet - currentSet

            if linesLeft:
                messages.append(
                    "%s contains entries not on the approved list" %
                    self.__target_file)
                for entry in linesLeft:
                    msg = "Found '%s' in '%s' " % (entry, fileName)
                    self.logger.notice(self.module_name, "Scan Fail: " + msg)

            if linesMissing:
                messages.append(
                    "%s is missing required entries from the approved list" %
                    self.__target_file)
                for entry in linesMissing:
                    msg = "Missing '%s' from '%s' " % (entry, fileName)
                    self.logger.notice(self.module_name, "Scan Fail: " + msg)

            if not linesLeft and not linesMissing:
                msg = "All required lines present in '%s'" % (fileName)
                self.logger.notice(self.module_name, msg)

            # In either case, we want to have /etc/shells *match* the approved list.
            # so for apply if we don't match, simply write out the approved list and
            # pass the old one back as a list to be restored.  No need for a patch file
            # *but* we our undo will be able to handle a patch set...

            if action in ['apply', 'undo'] and (linesLeft or linesMissing):
                try:
                    open(fileName, "w").writelines(
                        [entry + "\n" for entry in requiredSet])
                except OSError:
                    msg = "Unable to write '%s' with required lines." % fileName
                    self.logger.error(self.module_name, 'Apply Error: ' + msg)
                    raise tcs_utils.ActionError('%s %s' %
                                                (self.module_name, msg))
Example #11
0
                        msg = "allowed username '%s' not found in local user list - ignoring" % entry
                        self.logger.warn('sb_utils.file.fileperms.check_ownership',msg)
                # ok, user was given, do we *have* any acceptable entries?  If not punt without doing anything
                if not allowedUnames:
                    msg = "No valid unames found for acceptable file ownership - skipping %s" % pathname
                    raise tcs_utils.ActionError(msg)

            if 'if_user_is' in attribs:
                ifCurrentUname = attribs['if_user_is']
                ifCurrentUID  = self._map_uid_uname(ifCurrentUname)['uid']

            if 'group' in attribs:
                groupList = attribs['group']
                if type(groupList) == type(1):
                    groupList = "%d" % groupList
                groupList = tcs_utils.splitNaturally(groupList, wordAdditions="<>*-_", whitespaceAdditions=",", uniq=True)
                try:
                    idx = groupList.index('<SYSTEM>')
                    groupList = groupList [0:idx] + sb_utils.acctmgt.users.local_SystemGroups() + groupList[idx+1:]
                    groupList = tcs_utils.splitNaturally(groupList, wordAdditions="<>*-_", whitespaceAdditions=",", uniq=True)
                except ValueError, e:
                    pass

                for entry in groupList:
                    try:
                        allowedGIDs.append(self._map_gid_gname(entry)['gid'])
                        allowedGnames.append(entry)
                    except KeyError,e:
                        msg = "allowed groupname '%s' not found in local group list - ignoring" % entry
                        self.logger.warn('sb_utils.file.fileperms.check_ownership',msg)
                if not allowedGnames:
Example #12
0
    def _restrictCiphers(self, param, cipherLine, restrictions):
        """
           cipherLine holds the settings from the 'Ciphers' field
           restrictions is a dictionary with:
               mustStartWith = list of allowed starting fields
               mustContain   = list of allowed interior fields
               mustEndWith   = list of allowed ending fields 
           for each list, if an entry starts with '!' then this indicates negation of that entry
           each cipher is evaluated against each element of the list, and a non-matching finding == exclusion of that cipher
    
           For example, 
             startswith = aes 3des
             endswith   = !cbc
             
             would keep any cipher that starts with aes, starts with 3des, and does not end with cbc
             if the processed list winds up with *no* entries, then a "ManualActionRecq" exception is raised.
             
           The method returns the modified list of ciphers, and the list of rejected ciphers
        """

        acceptCiphers  = []
        rejectCiphers  = []
        messages       = []
        
        if not cipherLine:
            cipherLine = self.defaultCiphers
            msg = "No setting found for '%s' - using OS default as per man pages of '%s'" % (param, cipherLine)
            self.logger.info(self.module_name, msg)
            
        cipherList = tcs_utils.splitNaturally(cipherLine, wordAdditions='-:')

        if 'mustStartWith' in restrictions:
            allowedStarts, rejectedStarts = self._splitRestrictions(tcs_utils.splitNaturally(restrictions['mustStartWith'], wordAdditions='-:!'), prefix="^")
        if 'mustContain' in restrictions:
            allowedContains, rejectedContains = self._splitRestrictions(tcs_utils.splitNaturally(restrictions['mustContain'], wordAdditions='-:!'))
        if 'mustEndWith' in restrictions:
            allowedEnds, rejectedEnds = self._splitRestrictions(tcs_utils.splitNaturally(restrictions['mustEndWith'], wordAdditions='-:!'), suffix="$")

        acceptPattern = ".*".join ([pattern for pattern in [allowedStarts, allowedContains, allowedEnds] if pattern ])
        rejectPattern = ".*".join ([pattern for pattern in [rejectedStarts, rejectedContains, rejectedEnds] if pattern ])
                
        acceptRegex = re.compile(acceptPattern)
        rejectRegex = re.compile(rejectPattern)
    
        
        for cipher in cipherList:
            # by default we accept, unless the match fails
            acceptMatch = True
            if acceptPattern and not acceptRegex.search(cipher) : acceptMatch = False
            rejectMatch = False
            if rejectPattern and rejectRegex.search(cipher) : rejectMatch = True
            if acceptMatch and not rejectMatch:
                msg = "Cipher '%s' matched acceptable criteria" % cipher
                self.logger.debug(self.module_name+"._restrictCiphers", str(msg))
                acceptCiphers.append(cipher)
            else:
                msg = "Cipher '%s' did not match acceptable criteria" % cipher
                messages.append(msg)
                rejectCiphers.append(cipher)
            
        if not acceptCiphers:
            msg = "List of acceptable ciphers is empty - please configure '%s' manually " % self.configfile
            raise tcs_utils.ManualActionReqd("%s %s" % (self.module_name, msg))

        return ','.join(acceptCiphers), messages