diff options
Diffstat (limited to 'contrib/fix_private-bin.py')
-rwxr-xr-x | contrib/fix_private-bin.py | 157 |
1 files changed, 157 insertions, 0 deletions
diff --git a/contrib/fix_private-bin.py b/contrib/fix_private-bin.py new file mode 100755 index 000000000..270c758a2 --- /dev/null +++ b/contrib/fix_private-bin.py | |||
@@ -0,0 +1,157 @@ | |||
1 | #!/usr/bin/python3 | ||
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 | |||
30 | import sys, os, glob, re | ||
31 | |||
32 | privRx=re.compile("^(?:#\s*)?private-bin") | ||
33 | |||
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 | |||
40 | rxs=dict() | ||
41 | for (old,new) in replMap.items(): | ||
42 | rxs[old]=re.compile("\\b"+old+"\\b") | ||
43 | rxs[new]=re.compile("\\b"+new+"\\b") | ||
44 | #print(rxs) | ||
45 | |||
46 | for filename in files: | ||
47 | lines=None | ||
48 | with open(filename,"r") as file: | ||
49 | lines=file.readlines() | ||
50 | |||
51 | shouldUpdate=False | ||
52 | for (i,line) in enumerate(lines): | ||
53 | if privRx.search(line): | ||
54 | for (old,new) in replMap.items(): | ||
55 | if rxs[old].search(line) and not rxs[new].search(line): | ||
56 | lines[i]=rxs[old].sub(old+","+new, line) | ||
57 | shouldUpdate=True | ||
58 | print(lines[i]) | ||
59 | |||
60 | if shouldUpdate: | ||
61 | with open(filename,"w") as file: | ||
62 | file.writelines(lines) | ||
63 | pass | ||
64 | |||
65 | def createSetOfBinaries(files): | ||
66 | """ | ||
67 | Creates a set of binaries mentioned in private-bin directives of files. | ||
68 | """ | ||
69 | s=set() | ||
70 | for filename in files: | ||
71 | lines=None | ||
72 | with open(filename,"r") as file: | ||
73 | for line in file: | ||
74 | if privRx.search(line): | ||
75 | bins=line.split(",") | ||
76 | bins[0]=bins[0].split(" ")[-1] | ||
77 | bins = [n.strip() for n in bins] | ||
78 | s=s|set(bins) | ||
79 | return s | ||
80 | |||
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 | """ | ||
87 | m=dict() | ||
88 | toProcess=binariesSet | ||
89 | while len(toProcess)!=0: | ||
90 | additional=set() | ||
91 | for sh in toProcess: | ||
92 | for bD in binDirs: | ||
93 | p=bD+os.path.sep+sh | ||
94 | if os.path.exists(p): | ||
95 | if os.path.islink(p): | ||
96 | m[sh]=os.readlink(p) | ||
97 | additional.add(m[sh].split(" ")[0]) | ||
98 | else: | ||
99 | pass | ||
100 | break | ||
101 | toProcess=additional | ||
102 | return m | ||
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 | ||
150 | |||
151 | binDirs=["/bin","/usr/bin","/usr/sbin","/usr/local/bin","/usr/local/sbin"] | ||
152 | print("Binaries dirs are:") | ||
153 | print(binDirs) | ||
154 | doTheFixes(profilesPath, binDirs) | ||
155 | |||
156 | if __name__ == "__main__": | ||
157 | main() | ||