]> git.ipfire.org Git - people/stevee/selinux-policy.git/blame - support/genclassperms.py
Remove module for apt.
[people/stevee/selinux-policy.git] / support / genclassperms.py
CommitLineData
c04f2abe
CP
1#!/usr/bin/python
2
3# Author: Donald Miner <dminer@tresys.com>
4#
6b873c4d 5# Copyright (C) 2005 Tresys Technology, LLC
c04f2abe
CP
6# This program is free software; you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation, version 2.
9
10
11"""
12 This script generates an object class perm definition file.
13"""
14
15import sys
16
17USERSPACE_CLASS = "userspace"
18
19class Class:
20 """
21 This object stores an access vector class.
22 """
23
24 def __init__(self, name, perms, common):
25 # The name of the class.
26 self.name = name
27
28 # A list of permissions the class contains.
29 self.perms = perms
30
31 # True if the class is declared as common, False if not.
32 self.common = common
33
6e0542eb 34def get_perms(name, av_db, common):
c04f2abe
CP
35 """
36 Returns the list of permissions contained within an access vector
37 class that is stored in the access vector database av_db.
38 Returns an empty list if the object name is not found.
6e0542eb
CP
39 Specifiy whether get_perms is to return the class or the
40 common set of permissions with the boolean value 'common',
41 which is important in the case of having duplicate names (such as
42 class file and common file).
c04f2abe
CP
43 """
44
45 # Traverse through the access vector database and try to find the
46 # object with the name passed.
47 for obj in av_db:
6e0542eb 48 if obj.name == name and obj.common == common:
c04f2abe
CP
49 return obj.perms
50
51 return []
52
53def get_av_db(file_name):
54 """
55 Returns an access vector database generated from the file file_name.
56 """
a6df70c1
CP
57 # This function takes a file, reads the data, parses it and returns
58 # a list of access vector classes.
59 # Reading into av_data:
60 # The file specified will be read line by line. Each line will have
61 # its comments removed. Once comments are removed, each 'word' (text
62 # seperated by whitespace) and braces will be split up into seperate
63 # strings and appended to the av_data list, in the order they were
64 # read.
65 # Parsing av_data:
66 # Parsing is done using a queue implementation of the av_data list.
67 # Each time a word is used, it is dequeued afterwards. Each loop in
68 # the while loop below will read in key words and dequeue expected
69 # words and values. At the end of each loop, a Class containing the
70 # name, permissions and whether it is a common or not will be appended
71 # to the database. Lots of errors are caught here, almost all checking
72 # if a token is expected but EOF is reached.
73 # Now the list of Class objects is returned.
c04f2abe
CP
74
75 av_file = open(file_name, "r")
76 av_data = []
77 # Read the file and strip out comments on the way.
78 # At the end of the loop, av_data will contain a list of individual
79 # words. i.e. ['common', 'file', '{', ...]. All comments and whitespace
80 # will be gone.
81 while True:
82 av_line = av_file.readline()
83
84 # If EOF has been reached:
85 if not av_line:
86 break
87
88 # Check if there is a comment, and if there is, remove it.
89 comment_index = av_line.find("#")
90 if comment_index != -1:
91 av_line = av_line[:comment_index]
92
93 # Pad the braces with whitespace so that they are split into
94 # their own word. It doesn't matter if there will be extra
95 # white space, it'll get thrown away when the string is split.
96 av_line.replace("{"," { ")
97 av_line.replace("}"," } ")
98
99 # Split up the words on the line and add it to av_data.
100 av_data += av_line.split()
101
102 av_file.close()
103
104 # Parsing the file:
105 # The implementation of this parse is a queue. We use the list of words
106 # from av_data and use the front element, then dequeue it. Each
107 # loop of this while is a common or class declaration. Several
108 # expected tokens are parsed and dequeued out of av_data for each loop.
a6df70c1
CP
109 # At the end of the loop, database will contain a list of Class objects.
110 # i.e. [Class('name',['perm1','perm2',...],'True'), ...]
c04f2abe
CP
111 # Dequeue from the beginning of the list until av_data is empty:
112 database = []
113 while len(av_data) != 0:
114 # At the beginning of every loop, the next word should be
115 # "common" or "class", meaning that each loop is a common
116 # or class declaration.
117 # av_data = av_data[1:] removes the first element in the
118 # list, this is what is dequeueing data.
119
120 # Figure out whether the next class will be a common or a class.
121 if av_data[0] == "class":
122 common = False
123 elif av_data[0] == "common":
124 common = True
125 else:
126 error("Unexpected token in file " + file_name + ": "\
127 + av_data[0] + ".")
128
129 # Dequeue the "class" or "common" key word.
130 av_data = av_data[1:]
131
132 if len(av_data) == 0:
133 error("Missing token in file " + file_name + ".")
134
135 # Get and dequeue the name of the class or common.
136 name = av_data[0]
137 av_data = av_data[1:]
138
139 # Retrieve the permissions inherited from a common set:
140 perms = []
141 # If the object we are working with is a class, since only
142 # classes inherit:
143 if common == False:
144 if len(av_data) == 0:
145 error("Missing token in file " + file_name + ".")
146
147 # If the class inherits from something else:
148 if av_data[0] == "inherits":
149 # Dequeue the "inherits" key word.
150 av_data = av_data[1:]
151
152 if len(av_data) == 0:
153 error("Missing token in file "\
154 + file_name + " for " +\
155 keyword + " " + name + ".")
156
157 # av_data[0] is the name of the parent.
158 # Append the permissions of the parent to
159 # the current class' permissions.
6e0542eb
CP
160 perms += get_perms(av_data[0], database, True)
161
c04f2abe
CP
162 # Dequeue the name of the parent.
163 av_data = av_data[1:]
164
165 # Retrieve the permissions defined with this set.
166 if len(av_data) > 0 and av_data[0] == "{":
167 # Dequeue the "{"
168 av_data = av_data[1:]
169
170 # Keep appending permissions until a close brace is
171 # found.
172 while av_data[0] != "}":
173 if av_data[0] == "{":
174 error("Extra '{' in file " +\
175 file_name + ".")
176
177 # Add the permission name.
178 perms.append(av_data[0])
179
180 # Dequeue the permission name.
181 av_data = av_data[1:]
182
183 if len(av_data) == 0:
184 error("Missing token '}' in file "\
185 + file_name + ".")
186
187 # Dequeue the "}"
188 av_data = av_data[1:]
189
190 # Add the new access vector class to the database.
191 database.append(Class(name, perms, common))
192
193 return database
194
195def get_sc_db(file_name):
196 """
197 Returns a security class database generated from the file file_name.
198 """
199
200 # Read the file then close it.
201 sc_file = open(file_name)
202 sc_data = sc_file.readlines()
203 sc_file.close()
204
205 # For each line in the security classes file, add the name of the class
206 # and whether it is a userspace class or not to the security class
207 # database.
208 database = []
209 for line in sc_data:
210 line = line.lstrip()
211 # If the line is empty or the entire line is a comment, skip.
212 if line == "" or line[0] == "#":
213 continue
214
215 # Check if the comment to the right of the permission matches
216 # USERSPACE_CLASS.
217 comment_index = line.find("#")
218 if comment_index != -1 and line[comment_index+1:].strip() == USERSPACE_CLASS:
219 userspace = True
220 else:
221 userspace = False
222
223 # All lines should be in the format "class NAME", meaning
224 # it should have two tokens and the first token should be
225 # "class".
226 split_line = line.split()
227 if len(split_line) < 2 or split_line[0] != "class":
228 error("Wrong syntax: " + line)
229
230 # Add the class's name (split_line[1]) and whether it is a
231 # userspace class or not to the database.
232 # This is appending a tuple of (NAME,USERSPACE), where NAME is
233 # the name of the security class and USERSPACE is True if
234 # if it has "# USERSPACE_CLASS" on the end of the line, False
235 # if not.
236 database.append((split_line[1], userspace))
237
238 return database
239
240def gen_class_perms(av_db, sc_db):
241 """
242 Generates a class permissions document and returns it.
243 """
244
245 # Define class template:
246 class_perms_line = "define(`all_%s_perms',`{ %s}')\n"
247
248 # Generate the defines for the individual class permissions.
249 class_perms = ""
250 for obj in av_db:
251 # Don't output commons
252 if obj.common == True:
253 continue
254
6e0542eb
CP
255 # Get the list of permissions from the specified class.
256 perms = get_perms(obj.name, av_db, False)
c04f2abe
CP
257
258 # Merge all the permissions into one string with one space
259 # padding.
260 perm_str = ""
261 for perm in perms:
262 perm_str += perm + " "
263
264 # Add the line to the class_perms
265 class_perms += class_perms_line % (obj.name, perm_str)
266 class_perms += "\n"
267
268 # Generate the kernel_class_perms and userspace_class_perms sets.
269 class_line = "\tclass %s all_%s_perms;\n"
270 kernel_class_perms = "define(`all_kernel_class_perms',`\n"
271 userspace_class_perms = "define(`all_userspace_class_perms',`\n"
272 # For each (NAME,USERSPACE) tuple, add the class to the appropriate
273 # class permission set.
274 for name, userspace in sc_db:
275 if userspace:
276 userspace_class_perms += class_line % (name, name)
277 else:
278 kernel_class_perms += class_line % (name, name)
279 kernel_class_perms += "')\n\n"
280 userspace_class_perms += "')\n"
281
282 # Throw all the strings together and return the string.
283 return class_perms + kernel_class_perms + userspace_class_perms
284
285def error(error):
286 """
287 Print an error message and exit.
288 """
289
290 sys.stderr.write("%s exiting for: " % sys.argv[0])
291 sys.stderr.write("%s\n" % error)
292 sys.stderr.flush()
293 sys.exit(1)
294
295# MAIN PROGRAM
296app_name = sys.argv[0]
297
298if len(sys.argv) != 3:
299 error("Incorrect input.\nUsage: " + sys.argv[0] + " access_vectors security_classes" )
300
301# argv[1] is the access vector file.
302av_file = sys.argv[1]
303
304# argv[2] is the security class file.
305sc_file = sys.argv[2]
306
307# Output the class permissions document.
308sys.stdout.write(gen_class_perms(get_av_db(av_file), get_sc_db(sc_file)))