1import unittest, os, shutil, sys
2from tempfile import mkdtemp
3from subprocess import Popen, PIPE
4
5import argparse
6
7object_list = [ 'login', 'user', 'port', 'module', 'interface', 'node', 'fcontext', 'boolean','permissive', "dontaudit"]
8
9class SemanageTests(unittest.TestCase):
10    def assertDenied(self, err):
11        self.assertTrue('Permission denied' in err,
12                     '"Permission denied" not found in %r' % err)
13    def assertNotFound(self, err):
14        self.assertTrue('not found' in err,
15                     '"not found" not found in %r' % err)
16
17    def assertFailure(self, status):
18        self.assertTrue(status != 0,
19                     '"semanage succeeded when it should have failed')
20
21    def assertSuccess(self, status, err):
22        self.assertTrue(status == 0,
23                     '"semanage should have succeeded for this test %r' %  err)
24
25    def test_extract(self):
26        for object in object_list:
27            if object in ["dontaudit","module","permissive"]:
28                continue
29            "Verify semanage %s -E" % object
30            p = Popen(['semanage', object, '-E'], stdout = PIPE)
31            out, err = p.communicate()
32            self.assertSuccess(p.returncode, err)
33
34    def test_input_output(self):
35        print("Verify semanage export -f /tmp/out")
36        p = Popen(['semanage', "export", '-f', '/tmp/out'], stdout = PIPE)
37        out, err = p.communicate()
38        self.assertSuccess(p.returncode, err)
39        print("Verify semanage export -S targeted -f -")
40        p = Popen(["semanage","export","-S","targeted","-f","-"], stdout = PIPE)
41        out, err = p.communicate()
42        self.assertSuccess(p.returncode, err)
43        print("Verify semanage -S targeted -o -")
44        p = Popen(["semanage","-S","targeted","-o","-"], stdout = PIPE)
45        out, err = p.communicate()
46        self.assertSuccess(p.returncode, err)
47        print("Verify semanage import -f /tmp/out")
48        p = Popen(['semanage', "import", '-f', '/tmp/out'], stdout = PIPE)
49        out, err = p.communicate()
50        self.assertSuccess(p.returncode, err)
51        print("Verify semanage import -S targeted -f /tmp/out")
52        p = Popen(["semanage","import","-S","targeted","-f", "/tmp/out"], stdout = PIPE)
53        out, err = p.communicate()
54        self.assertSuccess(p.returncode, err)
55        print("Verify semanage -S targeted -i /tmp/out")
56        p = Popen(["semanage", "-S","targeted","-i", "/tmp/out"], stdout = PIPE)
57        out, err = p.communicate()
58        self.assertSuccess(p.returncode, err)
59
60    def test_list(self):
61        for object in object_list:
62            if object in ["dontaudit"]:
63                continue
64            "Verify semanage %s -l" % object
65            p = Popen(['semanage', object, '-l'], stdout = PIPE)
66            out, err = p.communicate()
67            self.assertSuccess(p.returncode, err)
68
69    def test_list_c(self):
70        for object in object_list:
71            if object in ["module", "permissive", "dontaudit"]:
72                continue
73            print("Verify semanage %s -l" % object)
74            p = Popen(['semanage', object, '-lC'], stdout = PIPE)
75            out, err = p.communicate()
76            self.assertSuccess(p.returncode, err)
77
78    def test_fcontext(self):
79            p = Popen(["semanage", "fcontext", "-d", "/ha-web(/.*)?" ], stderr = PIPE)
80            out, err = p.communicate()
81
82            print("Verify semanage fcontext -a")
83            p = Popen(["semanage", "fcontext", "-a", "-t", "httpd_sys_content_t", "/ha-web(/.*)?" ], stdout = PIPE)
84            out, err = p.communicate()
85            self.assertSuccess(p.returncode, err)
86            print("Verify semanage fcontext -m")
87            p = Popen(["semanage", "fcontext", "-m", "-t", "default_t", "/ha-web(/.*)?" ], stdout = PIPE)
88            out, err = p.communicate()
89            self.assertSuccess(p.returncode, err)
90            print("Verify semanage fcontext -d")
91            p = Popen(["semanage", "fcontext", "-d", "/ha-web(/.*)?" ], stdout = PIPE)
92            out, err = p.communicate()
93            self.assertSuccess(p.returncode, err)
94
95    def test_fcontext_e(self):
96            p = Popen(["semanage", "fcontext", "-d", "/myhome" ], stderr = PIPE)
97            out, err = p.communicate()
98            p = Popen(["semanage", "fcontext", "-d", "/myhome1" ], stderr = PIPE)
99            out, err = p.communicate()
100
101            print("Verify semanage fcontext -a -e")
102            p = Popen(["semanage", "fcontext", "-a", "-e", "/home", "/myhome" ], stdout = PIPE)
103            out, err = p.communicate()
104            self.assertSuccess(p.returncode, err)
105            print("Verify semanage fcontext -m -e")
106            p = Popen(["semanage", "fcontext", "-a", "-e", "/home", "/myhome1" ], stdout = PIPE)
107            out, err = p.communicate()
108            self.assertSuccess(p.returncode, err)
109            print("Verify semanage fcontext -d -e")
110            p = Popen(["semanage", "fcontext", "-d", "/myhome1" ], stdout = PIPE)
111            out, err = p.communicate()
112            self.assertSuccess(p.returncode, err)
113
114    def test_port(self):
115            # Cleanup
116            p = Popen(["semanage", "port", "-d", "-p", "tcp", "55" ], stdout = PIPE, stderr = PIPE)
117            out, err = p.communicate()
118
119            # test
120            print("Verify semanage port -a")
121            p = Popen(["semanage", "port", "-a", "-t", "ssh_port_t", "-p", "tcp", "55" ], stdout = PIPE)
122            out, err = p.communicate()
123            self.assertSuccess(p.returncode, err)
124            print("Verify semanage port -m")
125            p = Popen(["semanage", "port", "-m", "-t", "http_port_t", "-p", "tcp", "55" ], stdout = PIPE)
126            out, err = p.communicate()
127            self.assertSuccess(p.returncode, err)
128            print("Verify semanage port -d")
129            p = Popen(["semanage", "port", "-d", "-p", "tcp", "55" ], stdout = PIPE)
130            out, err = p.communicate()
131            self.assertSuccess(p.returncode, err)
132
133    def test_login(self):
134            # Cleanup
135            p = Popen(["userdel", "-f", "-r", "testlogin" ], stderr = PIPE, stdout = PIPE)
136            out, err = p.communicate()
137            p = Popen(["semanage", "user", "-d", "testuser_u" ], stderr = PIPE, stdout = PIPE)
138            out, err = p.communicate()
139            p = Popen(["semanage", "login", "-d", "testlogin" ], stderr = PIPE, stdout = PIPE)
140            out, err = p.communicate()
141
142            #test
143            print("Verify semanage user -a")
144            p = Popen(["semanage", "user", "-a", "-R", "staff_r", "-r", "s0-s0:c0.c1023", "testuser_u" ], stdout = PIPE)
145            out, err = p.communicate()
146            self.assertSuccess(p.returncode, err)
147            print("Verify useradd ")
148            p = Popen(["useradd", "testlogin" ], stdout = PIPE)
149            out, err = p.communicate()
150            self.assertSuccess(p.returncode, err)
151            print("Verify semanage login -a")
152            p = Popen(["semanage", "login", "-a", "-s", "testuser_u", "testlogin" ], stdout = PIPE)
153            out, err = p.communicate()
154            self.assertSuccess(p.returncode, err)
155            print("Verify semanage login -m -r")
156            p = Popen(["semanage", "login", "-m", "-r", "s0-s0:c1", "testlogin" ], stdout = PIPE)
157            out, err = p.communicate()
158            self.assertSuccess(p.returncode, err)
159            print("Verify semanage login -m -s")
160            p = Popen(["semanage", "login", "-m", "-s", "staff_u", "testlogin" ], stdout = PIPE)
161            out, err = p.communicate()
162            self.assertSuccess(p.returncode, err)
163            print("Verify semanage login -m -s -r")
164            p = Popen(["semanage", "login", "-m", "-s", "testuser_u", "-r", "s0", "testlogin" ], stdout = PIPE)
165            out, err = p.communicate()
166            self.assertSuccess(p.returncode, err)
167            print("Verify semanage login -d")
168            p = Popen(["semanage", "login", "-d", "testlogin" ], stdout = PIPE)
169            out, err = p.communicate()
170            print("Verify userdel ")
171            p = Popen(["userdel", "-f", "-r", "testlogin" ], stderr = PIPE, stdout = PIPE)
172            out, err = p.communicate()
173            self.assertSuccess(p.returncode, err)
174            print("Verify semanage user -d")
175            p = Popen(["semanage", "user", "-d", "testuser_u" ], stdout = PIPE)
176            out, err = p.communicate()
177            self.assertSuccess(p.returncode, err)
178
179    def test_user(self):
180            # Cleanup
181            p = Popen(["semanage", "user", "-d", "testuser_u" ], stderr = PIPE, stdout = PIPE)
182            out, err = p.communicate()
183
184            # test
185            print("Verify semanage user -a")
186            p = Popen(["semanage", "user", "-a", "-R", "staff_r", "-r", "s0-s0:c0.c1023", "testuser_u" ], stdout = PIPE)
187            out, err = p.communicate()
188            self.assertSuccess(p.returncode, err)
189            print("Verify semanage user -m -R")
190            p = Popen(["semanage", "user", "-m", "-R", "sysadm_r unconfined_r", "testuser_u" ], stdout = PIPE)
191            out, err = p.communicate()
192            self.assertSuccess(p.returncode, err)
193            print("Verify semanage user -m -r")
194            p = Popen(["semanage", "user", "-m", "-r", "s0-s0:c1", "testuser_u" ], stdout = PIPE)
195            out, err = p.communicate()
196            self.assertSuccess(p.returncode, err)
197            print("Verify semanage user -d")
198            p = Popen(["semanage", "user", "-d", "testuser_u" ], stdout = PIPE)
199            out, err = p.communicate()
200            self.assertSuccess(p.returncode, err)
201
202    def test_boolean(self):
203        import selinux
204        boolean_status={0:"--off",1:"--on"}
205        boolean_state=selinux.security_get_boolean_active("httpd_anon_write")
206        # Test
207        print("Verify semanage boolean -m %s httpd_anon_write" % boolean_status[not boolean_state])
208        p = Popen(["semanage","boolean","-m",boolean_status[(not boolean_state)],"httpd_anon_write"], stdout = PIPE)
209        out, err = p.communicate()
210        self.assertSuccess(p.returncode, err)
211        print("Verify semanage boolean -m %s httpd_anon_write" % boolean_status[boolean_state])
212        p = Popen(["semanage","boolean","-m",boolean_status[boolean_state],"httpd_anon_write"], stdout = PIPE)
213        out, err = p.communicate()
214        self.assertSuccess(p.returncode, err)
215
216def semanage_suite():
217    semanage_suite = unittest.TestSuite()
218    semanage_suite.addTest(unittest.makeSuite(SemanageTests))
219
220    return semanage_suite
221
222def semanage_custom_suite(test_list):
223    suiteSemanage=unittest.TestSuite()
224    for t in test_list:
225        suiteSemanage.addTest(SemanageTests(t))
226
227    return suiteSemanage
228
229def semanage_run_test(suite):
230    unittest.TextTestRunner(verbosity=2).run(suite)
231
232class CheckTest(argparse.Action):
233    def __call__(self, parser, namespace, values, option_string=None):
234        newval = getattr(namespace, self.dest)
235        if not newval:
236            newval = []
237        for v in values:
238            if v not in semanage_test_list:
239                raise ValueError("%s must be an unit test.\nValid tests: %s" % (v, ", ".join(semanage_test_list)))
240            newval.append(v)
241        setattr(namespace, self.dest, newval)
242
243def semanage_args(args):
244    if args.list:
245        print("You can run the following tests:")
246        for i in semanage_test_list:
247            print(i)
248    if args.all:
249        semanage_run_test(semanage_suite())
250    if args.test:
251        semanage_run_test(semanage_custom_suite(args.test))
252
253def gen_semanage_test_args(parser):
254    group = parser.add_mutually_exclusive_group(required=True)
255    group.add_argument('-a', "--all", dest="all", default=False,
256                        action="store_true",
257                        help=("Run all semanage unit tests"))
258    group.add_argument('-l', "--list", dest="list", default=False,
259                        action="store_true",
260                        help=("List all semanage unit tests"))
261    group.add_argument('-t', "--test", dest="test", default=[],
262                        action=CheckTest, nargs="*",
263                        help=("Run selected semanage unit test(s)"))
264    group.set_defaults(func=semanage_args)
265
266if __name__ == "__main__":
267    import selinux
268    semanage_test_list=filter(lambda x: x.startswith("test_"), dir(SemanageTests))
269    if selinux.security_getenforce() == 1:
270        parser = argparse.ArgumentParser(description='Semanage unit test script')
271        gen_semanage_test_args(parser)
272        try:
273            args = parser.parse_args()
274            args.func(args)
275            sys.exit(0)
276        except ValueError,e:
277            sys.stderr.write("%s: %s\n" % (e.__class__.__name__, str(e)))
278            sys.exit(1)
279        except IOError,e:
280            sys.stderr.write("%s: %s\n" % (e.__class__.__name__, str(e)))
281            sys.exit(1)
282        except KeyboardInterrupt:
283            sys.exit(0)
284    else:
285        print("SELinux must be in enforcing mode for this test")
286