From 80965e6a7f7ec62ba2c5385a320018adb5463c73 Mon Sep 17 00:00:00 2001 From: KOLANICH Date: Wed, 4 Jan 2017 18:54:33 +0300 Subject: Improved fix_private-bin.py a bit: added commandline arguments, metainfo and breadth-first search --- contrib/fix_private-bin.py | 129 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 109 insertions(+), 20 deletions(-) diff --git a/contrib/fix_private-bin.py b/contrib/fix_private-bin.py index 705e46e46..270c758a2 100755 --- a/contrib/fix_private-bin.py +++ b/contrib/fix_private-bin.py @@ -1,15 +1,47 @@ #!/usr/bin/python3 +__author__ = "KOLANICH" +__copyright__ = """This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to """ +__license__ = "Unlicense" + import sys, os, glob, re privRx=re.compile("^(?:#\s*)?private-bin") def fixSymlinkedBins(files, replMap): + """ + Used to add filenames to private-bin directives of files if the ones present are mentioned in replMap + replMap is a dict where key is the marker filename and value is the filename to add + """ + rxs=dict() for (old,new) in replMap.items(): rxs[old]=re.compile("\\b"+old+"\\b") rxs[new]=re.compile("\\b"+new+"\\b") - print(rxs) + #print(rxs) for filename in files: lines=None @@ -28,9 +60,12 @@ def fixSymlinkedBins(files, replMap): if shouldUpdate: with open(filename,"w") as file: file.writelines(lines) - pass + pass -def createListOfBinaries(files): +def createSetOfBinaries(files): + """ + Creates a set of binaries mentioned in private-bin directives of files. + """ s=set() for filename in files: lines=None @@ -44,25 +79,79 @@ def createListOfBinaries(files): return s def createSymlinkTable(binDirs, binariesSet): + """ + creates a dict of symlinked binaries in the system where a key is a symlink name and value is a symlinked binary. + binDirs are folders to look into for binaries symlinks + binariesSet is a set of binaries to be checked if they are actually a symlinks + """ m=dict() - for sh in binariesSet: - for bD in binDirs: - p=bD+os.path.sep+sh - if os.path.exists(p): - if os.path.islink(p): - m[sh]=os.readlink(p) - else: - pass - break + toProcess=binariesSet + while len(toProcess)!=0: + additional=set() + for sh in toProcess: + for bD in binDirs: + p=bD+os.path.sep+sh + if os.path.exists(p): + if os.path.islink(p): + m[sh]=os.readlink(p) + additional.add(m[sh].split(" ")[0]) + else: + pass + break + toProcess=additional return m +def doTheFixes(profilesPath, binDirs): + """ + Fixes private-bin in .profiles for firejail. The pipeline is as follows: + discover files -> discover mentioned binaries -> + discover the ones which are symlinks -> + make a look-up table for fix -> + filter the ones can be fixed (we cannot fix the ones which are not in directories for binaries) -> + apply fix + """ + files=glob.glob(profilesPath+os.path.sep+"*.profile") + bins=createSetOfBinaries(files) + #print("The binaries used are:") + #print(bins) + stbl=createSymlinkTable(binDirs,bins) + print("The replacement table is:") + print(stbl) + stbl={a[0]:a[1] for a in stbl.items() if a[0].find(os.path.sep) < 0 and a[1].find(os.path.sep)<0} + print("Filtered replacement table is:") + print(stbl) + fixSymlinkedBins(files,stbl) + +def printHelp(): + print("python3 "+os.path.basename(__file__)+" \nThe default dir is "+defaultProfilesPath+"\n"+doTheFixes.__doc__) + +def main(): + """The main function. Parses the commandline args, shows messages and calles the function actually doing the work.""" + print(repr(sys.argv)) + defaultProfilesPath="../etc" + if len(sys.argv)>2 or (len(sys.argv)==2 and (sys.argv[1] == '-h' or sys.argv[1] == '--help') ): + printHelp() + exit(1) + + profilesPath=None + if len(sys.argv)==2: + if os.path.isdir(sys.argv[1]): + profilesPath=os.path.abspath(sys.argv[1]) + else: + if os.path.exists(sys.argv[1]): + print(sys.argv[1]+" is not a dir") + else: + print(sys.argv[1]+" does not exist") + printHelp() + exit(1) + else: + print("Using default profiles dir: " + defaultProfilesPath) + profilesPath=defaultProfilesPath -sh="sh" -binDirs=["/bin","/usr/bin","/usr/sbin","/usr/local/bin","/usr/local/sbin"] -profilesPath="." -files=glob.glob(profilesPath+os.path.sep+"*.profile") + binDirs=["/bin","/usr/bin","/usr/sbin","/usr/local/bin","/usr/local/sbin"] + print("Binaries dirs are:") + print(binDirs) + doTheFixes(profilesPath, binDirs) -bins=createListOfBinaries(files) -stbl=createSymlinkTable(binDirs,bins) -print(stbl) -fixSymlinkedBins(files,{a[0]:a[1] for a in stbl.items() if a[0].find("/") < 0 and a[1].find("/")<0}) +if __name__ == "__main__": + main() -- cgit v1.2.3-70-g09d2