diff options
-rwxr-xr-x | contrib/fix_private-bin.py | 129 |
1 files 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 @@ | |||
1 | #!/usr/bin/python3 | 1 | #!/usr/bin/python3 |
2 | 2 | ||
3 | __author__ = "KOLANICH" | ||
4 | __copyright__ = """This is free and unencumbered software released into the public domain. | ||
5 | |||
6 | Anyone is free to copy, modify, publish, use, compile, sell, or | ||
7 | distribute this software, either in source code form or as a compiled | ||
8 | binary, for any purpose, commercial or non-commercial, and by any | ||
9 | means. | ||
10 | |||
11 | In jurisdictions that recognize copyright laws, the author or authors | ||
12 | of this software dedicate any and all copyright interest in the | ||
13 | software to the public domain. We make this dedication for the benefit | ||
14 | of the public at large and to the detriment of our heirs and | ||
15 | successors. We intend this dedication to be an overt act of | ||
16 | relinquishment in perpetuity of all present and future rights to this | ||
17 | software under copyright law. | ||
18 | |||
19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
20 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
21 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||
22 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
23 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
24 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
25 | OTHER DEALINGS IN THE SOFTWARE. | ||
26 | |||
27 | For more information, please refer to <http://unlicense.org/>""" | ||
28 | __license__ = "Unlicense" | ||
29 | |||
3 | import sys, os, glob, re | 30 | import sys, os, glob, re |
4 | 31 | ||
5 | privRx=re.compile("^(?:#\s*)?private-bin") | 32 | privRx=re.compile("^(?:#\s*)?private-bin") |
6 | 33 | ||
7 | def fixSymlinkedBins(files, replMap): | 34 | def fixSymlinkedBins(files, replMap): |
35 | """ | ||
36 | Used to add filenames to private-bin directives of files if the ones present are mentioned in replMap | ||
37 | replMap is a dict where key is the marker filename and value is the filename to add | ||
38 | """ | ||
39 | |||
8 | rxs=dict() | 40 | rxs=dict() |
9 | for (old,new) in replMap.items(): | 41 | for (old,new) in replMap.items(): |
10 | rxs[old]=re.compile("\\b"+old+"\\b") | 42 | rxs[old]=re.compile("\\b"+old+"\\b") |
11 | rxs[new]=re.compile("\\b"+new+"\\b") | 43 | rxs[new]=re.compile("\\b"+new+"\\b") |
12 | print(rxs) | 44 | #print(rxs) |
13 | 45 | ||
14 | for filename in files: | 46 | for filename in files: |
15 | lines=None | 47 | lines=None |
@@ -28,9 +60,12 @@ def fixSymlinkedBins(files, replMap): | |||
28 | if shouldUpdate: | 60 | if shouldUpdate: |
29 | with open(filename,"w") as file: | 61 | with open(filename,"w") as file: |
30 | file.writelines(lines) | 62 | file.writelines(lines) |
31 | pass | 63 | pass |
32 | 64 | ||
33 | def createListOfBinaries(files): | 65 | def createSetOfBinaries(files): |
66 | """ | ||
67 | Creates a set of binaries mentioned in private-bin directives of files. | ||
68 | """ | ||
34 | s=set() | 69 | s=set() |
35 | for filename in files: | 70 | for filename in files: |
36 | lines=None | 71 | lines=None |
@@ -44,25 +79,79 @@ def createListOfBinaries(files): | |||
44 | return s | 79 | return s |
45 | 80 | ||
46 | def createSymlinkTable(binDirs, binariesSet): | 81 | def createSymlinkTable(binDirs, binariesSet): |
82 | """ | ||
83 | creates a dict of symlinked binaries in the system where a key is a symlink name and value is a symlinked binary. | ||
84 | binDirs are folders to look into for binaries symlinks | ||
85 | binariesSet is a set of binaries to be checked if they are actually a symlinks | ||
86 | """ | ||
47 | m=dict() | 87 | m=dict() |
48 | for sh in binariesSet: | 88 | toProcess=binariesSet |
49 | for bD in binDirs: | 89 | while len(toProcess)!=0: |
50 | p=bD+os.path.sep+sh | 90 | additional=set() |
51 | if os.path.exists(p): | 91 | for sh in toProcess: |
52 | if os.path.islink(p): | 92 | for bD in binDirs: |
53 | m[sh]=os.readlink(p) | 93 | p=bD+os.path.sep+sh |
54 | else: | 94 | if os.path.exists(p): |
55 | pass | 95 | if os.path.islink(p): |
56 | break | 96 | m[sh]=os.readlink(p) |
97 | additional.add(m[sh].split(" ")[0]) | ||
98 | else: | ||
99 | pass | ||
100 | break | ||
101 | toProcess=additional | ||
57 | return m | 102 | return m |
58 | 103 | ||
104 | def doTheFixes(profilesPath, binDirs): | ||
105 | """ | ||
106 | Fixes private-bin in .profiles for firejail. The pipeline is as follows: | ||
107 | discover files -> discover mentioned binaries -> | ||
108 | discover the ones which are symlinks -> | ||
109 | make a look-up table for fix -> | ||
110 | filter the ones can be fixed (we cannot fix the ones which are not in directories for binaries) -> | ||
111 | apply fix | ||
112 | """ | ||
113 | files=glob.glob(profilesPath+os.path.sep+"*.profile") | ||
114 | bins=createSetOfBinaries(files) | ||
115 | #print("The binaries used are:") | ||
116 | #print(bins) | ||
117 | stbl=createSymlinkTable(binDirs,bins) | ||
118 | print("The replacement table is:") | ||
119 | print(stbl) | ||
120 | 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} | ||
121 | print("Filtered replacement table is:") | ||
122 | print(stbl) | ||
123 | fixSymlinkedBins(files,stbl) | ||
124 | |||
125 | def printHelp(): | ||
126 | print("python3 "+os.path.basename(__file__)+" <dir with .profile files>\nThe default dir is "+defaultProfilesPath+"\n"+doTheFixes.__doc__) | ||
127 | |||
128 | def main(): | ||
129 | """The main function. Parses the commandline args, shows messages and calles the function actually doing the work.""" | ||
130 | print(repr(sys.argv)) | ||
131 | defaultProfilesPath="../etc" | ||
132 | if len(sys.argv)>2 or (len(sys.argv)==2 and (sys.argv[1] == '-h' or sys.argv[1] == '--help') ): | ||
133 | printHelp() | ||
134 | exit(1) | ||
135 | |||
136 | profilesPath=None | ||
137 | if len(sys.argv)==2: | ||
138 | if os.path.isdir(sys.argv[1]): | ||
139 | profilesPath=os.path.abspath(sys.argv[1]) | ||
140 | else: | ||
141 | if os.path.exists(sys.argv[1]): | ||
142 | print(sys.argv[1]+" is not a dir") | ||
143 | else: | ||
144 | print(sys.argv[1]+" does not exist") | ||
145 | printHelp() | ||
146 | exit(1) | ||
147 | else: | ||
148 | print("Using default profiles dir: " + defaultProfilesPath) | ||
149 | profilesPath=defaultProfilesPath | ||
59 | 150 | ||
60 | sh="sh" | 151 | binDirs=["/bin","/usr/bin","/usr/sbin","/usr/local/bin","/usr/local/sbin"] |
61 | binDirs=["/bin","/usr/bin","/usr/sbin","/usr/local/bin","/usr/local/sbin"] | 152 | print("Binaries dirs are:") |
62 | profilesPath="." | 153 | print(binDirs) |
63 | files=glob.glob(profilesPath+os.path.sep+"*.profile") | 154 | doTheFixes(profilesPath, binDirs) |
64 | 155 | ||
65 | bins=createListOfBinaries(files) | 156 | if __name__ == "__main__": |
66 | stbl=createSymlinkTable(binDirs,bins) | 157 | main() |
67 | print(stbl) | ||
68 | fixSymlinkedBins(files,{a[0]:a[1] for a in stbl.items() if a[0].find("/") < 0 and a[1].find("/")<0}) | ||