def __buildTree(self, stash): _nodes = [] for x in [x for x in stash if x.Key in ["After"]]: _n = None _m = None try: _t = [y for y in _nodes if y.name == x.Value] if not any(_t): _n = Node(x.Value) _nodes.append(_n) else: _n = _t[0] _t = [y for y in _nodes if y.name == x.UnitName] if not any(_t): _m = Node(x.UnitName) _nodes.append(_m) else: _m = _t[0] if _m not in _n.children: _n.children += (_m, ) except LoopError as e: _path = self.__getNodeFromException(str(e)) + [x.UnitName] stash.append( UnitItem(file=x.File, line=x.Line, preerror=[ ErrorCyclicDependency(_path, x.Line, x.File) ])) for x in [x for x in stash if x.Key in ["Before"]]: try: _n = None _t = [y for y in _nodes if y.name == x.UnitName] if not any(_t): _n = Node(x.UnitName) _nodes.append(_n) else: _n = _t[0] _t = [y for y in _nodes if y.name == x.Value] _m = None if not any(_t): _m = Node(x.Value) _nodes.append(_m) else: _m = _t[0] if _m not in _n.children: _n.children += (_m, ) except LoopError as e: _path = [x.UnitName] + self.__getNodeFromException(str(e)) stash.append( UnitItem(file=x.File, line=x.Line, preerror=[ ErrorCyclicDependency(_path, x.Line, x.File) ])) return stash
def __access_subgroups(self, stash): res = [] if not stash: return res if self.__is_priv_user(stash): return res if not UnitItem( file="magicfoo", section="Service", key="SupplementaryGroups").IsValidInVersion(self.__version): return res for _x in [x for x in stash if x.Key == "SupplementaryGroups"]: res.append( UnitItem(file=_x.File, line=_x.Line, preerror=[ ErrorSecurity( "Service should not use {}".format(_x.Key), _x.File, "SupplementaryGroups", _x.Line) ])) return res
def __access_remove_ipc(self, stash): res = [] if not stash: return res if self.__is_priv_user(stash): return res if not UnitItem(file="magicfoo", section="Service", key="RemoveIPC").IsValidInVersion(self.__version): return res for _x in [x for x in stash if x.Key == "RemoveIPC"]: if _x.Value not in ["yes", "on", "1", "true"]: res.append( UnitItem(file=_x.File, line=_x.Line, preerror=[ ErrorSecurity( "Service should set activate {}".format( _x.Key), _x.File, "RemoveIPC", _x.Line) ])) return res
def __access_logical_sets(self, stash, key, badvalues, emptybad=False): res = [] if not stash: return res _file = stash[0].File # get effective set first _effcaps = set() for c in [x for x in stash if x.Key == key]: _notmode = c.Value.startswith("~") if not c.Value: _effcaps = set() for sc in c.Value.lstrip("~").split(" "): if sc: if _notmode: _effcaps.discard(sc) else: _effcaps.add(sc) for b in badvalues: if b in _effcaps: res.append( UnitItem( file=_file, line=1, preerror=[ ErrorSecurity( "Service sets not-recommended {} in {}".format( b, key), _file, key) ])) if not _effcaps and emptybad: res.append( UnitItem( file=_file, line=1, preerror=[ ErrorSecurity( "Service doesn't set recommended {}".format(key), _file, key) ])) return res
def __access_user(self, stash): res = [] if not stash: return res _file = stash[0].File # User _dynuser = [x for x in stash if x.Key == "DynamicUser"] _user = [x for x in stash if x.Key == "User"] if not _dynuser and not _user: res.append( UnitItem(file=_file, line=1, preerror=[ ErrorSecurity( "Neither User nor DynamicUser is set", _file, "NoUser") ])) for u in _dynuser + _user: if u.Value in ["0", "root"]: res.append( UnitItem( file=u.File, line=u.Line, preerror=[ ErrorSecurity( "Service should not run under {}=root".format( u.Key), u.File, "UserRoot", u.Line) ])) if u.Value in ["nobody"]: res.append( UnitItem(file=u.File, line=u.Line, preerror=[ ErrorSecurity( "Service should not run under {}=nobody". format(u.Key), u.File, "UserNobody", u.Line) ])) return res
def Run(self, stash, runargs): uniqunits = list(set([x.UnitName for x in stash])) for u in uniqunits: execstarts = [ x for x in stash if x.Section == "Service" and x.Key == "ExecStart" and x.UnitName == u ] servtype = [ x for x in stash if x.Section == "Service" and x.Key == "Type" and x.UnitName == u ] oneshots = [x for x in servtype if x.Value == "oneshot"] if any(oneshots): if not any(execstarts): for i in oneshots: stash.append( UnitItem( file=i.File, line=i.Line, preerror=[ ErrorMultiplicity( "oneshot services require at least one ExecStart", i.Line, i.File) ])) else: if len(execstarts) > 1: for i in execstarts[1:]: stash.append( UnitItem( file=i.File, line=i.Line, preerror=[ ErrorMultiplicity( "This type of unit can only have 1 ExecStart setting", i.Line, i.File) ])) return stash
def __parseFile(self, file, runargs): res = [] __x = SystemdUnitParser() if not os.path.isfile(file): return res with open(file) as i: try: __x.read_file(i) except (MissingSectionHeaderError) as e: _file, fileext = os.path.splitext(file) if fileext in KNOWN_UNITS_EXT: msg = e.message.split("\n")[0] res.append( UnitItem(file=file, line=e.lineno, preerror=[ErrorSyntaxError(msg, 1, file)])) else: return res except (ParsingError) as e: _file, fileext = os.path.splitext(file) if fileext in KNOWN_UNITS_EXT: msg = e.message.split("\n")[0] res.append( UnitItem(file=file, line=1, preerror=[ErrorSyntaxError(msg, 1, file)])) else: return res except UnicodeDecodeError: # This seems to be a binary return res for section in dict(__x).keys(): for k, v in dict(__x[section]).items(): if isinstance(v, tuple) or isinstance(v, list): for i in v: res.append( UnitItem(file=file, line=self.__getLineFromFile( file, [k, "=", i]), section=section, key=k, value=i)) else: res.append( UnitItem(file=file, line=self.__getLineFromFile( file, [k, "=", v]), section=section, key=k, value=v)) _file, fileext = os.path.splitext(file) _filemode = os.stat(file).st_mode _filemodeExpected = [0o100644, 0o100660, 0o100664, 0o100640] if "Unit" not in dict( __x).keys() and fileext in KNOWN_UNITS_MUST_HAVE_UNITSECTION: res.append( UnitItem(file=file, preerror=[ErrorUnitSectionMissing(file)])) if fileext and fileext not in KNOWN_UNITS_EXT: res.append( UnitItem(file=file, preerror=[ErrorUnknownUnitType(fileext, file)])) if _filemode not in _filemodeExpected: res.append( UnitItem(file=file, preerror=[ ErrorFileMaskWrong(_filemode, _filemodeExpected, file) ])) if not runargs.nodropins: for p in GetDropinPaths(os.path.basename(file), runargs): for f in glob.glob(p): d_res = self.__parseFile(f, runargs) for item in d_res: res = item.RunDropInProcessor(res, runargs) for k, v in KNOWN_MANDATORY.items(): if k in dict(__x).keys(): for opt in v: if not any( [x for x in res if x.Section == k and x.Key == opt]): res.append( UnitItem(file=file, preerror=[ ErrorMandatoryOptionMissing( opt, k, file) ])) for k in SPECIALS_SINGLEITEM: # Catch all the special cases res = k.Run(res, self.__runargs) return list(set(res))