1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
|
#!/usr/bin/env python
import sys
import os
import argparse
class FileContextsNode:
path = None
fileType = None
context = None
Type = None
meta = None
stemLen = None
strLen = None
Type = None
line = None
def __init__(self, path, fileType, context, meta, stemLen, strLen, line):
self.path = path
self.fileType = fileType
self.context = context
self.meta = meta
self.stemLen = stemLen
self.strlen = strLen
self.Type = context.split(":")[2]
self.line = line
metaChars = frozenset(['.', '^', '$', '?', '*', '+', '|', '[', '(', '{'])
escapedMetaChars = frozenset(['\.', '\^', '\$', '\?', '\*', '\+', '\|', '\[', '\(', '\{'])
def getStemLen(path):
global metaChars
stemLen = 0
i = 0
while i < len(path):
if path[i] == "\\":
i += 1
elif path[i] in metaChars:
break
stemLen += 1
i += 1
return stemLen
def getIsMeta(path):
global metaChars
global escapedMetaChars
metaCharsCount = 0
escapedMetaCharsCount = 0
for c in metaChars:
if c in path:
metaCharsCount += 1
for c in escapedMetaChars:
if c in path:
escapedMetaCharsCount += 1
return metaCharsCount > escapedMetaCharsCount
def CreateNode(line):
global metaChars
if (len(line) == 0) or (line[0] == '#'):
return None
split = line.split()
path = split[0].strip()
context = split[-1].strip()
fileType = None
if len(split) == 3:
fileType = split[1].strip()
meta = getIsMeta(path)
stemLen = getStemLen(path)
strLen = len(path.replace("\\", ""))
return FileContextsNode(path, fileType, context, meta, stemLen, strLen, line)
def ReadFileContexts(files):
fc = []
for f in files:
fd = open(f)
for line in fd:
node = CreateNode(line.strip())
if node != None:
fc.append(node)
return fc
# Comparator function for list.sort() based off of fc_sort.c
# Compares two FileContextNodes a and b and returns 1 if a is more
# specific or -1 if b is more specific.
def compare(a, b):
# The regex without metachars is more specific
if a.meta and not b.meta:
return -1
if b.meta and not a.meta:
return 1
# The regex with longer stemlen (regex before any meta characters) is more specific.
if a.stemLen < b.stemLen:
return -1
if b.stemLen < a.stemLen:
return 1
# The regex with longer string length is more specific
if a.strLen < b.strLen:
return -1
if b.strLen < a.strLen:
return 1
# A regex with a fileType defined (e.g. file, dir) is more specific.
if a.fileType is None and b.fileType is not None:
return -1
if b.fileType is None and a.fileType is not None:
return 1
# Regexes are equally specific.
return 0
def FcSort(files):
for f in files:
if not os.path.exists(f):
sys.exit("Error: File_contexts file " + f + " does not exist\n")
Fc = ReadFileContexts(files)
Fc.sort(cmp=compare)
return Fc
def PrintFc(Fc, out):
if not out:
f = sys.stdout
else:
f = open(out, "w")
for node in Fc:
f.write(node.line + "\n")
if __name__ == '__main__':
parser = argparse.ArgumentParser(description="SELinux file_contexts sorting tool.")
parser.add_argument("-i", dest="input", help="Path to the file_contexts file(s).", nargs="?", action='append')
parser.add_argument("-o", dest="output", help="Path to the output file", nargs=1)
args = parser.parse_args()
if not args.input:
parser.error("Must include path to policy")
if not not args.output:
args.output = args.output[0]
PrintFc(FcSort(args.input),args.output)
|