blob: 12745b3d45bb169c1c9ec1f62227e21b145f27ee [file] [log] [blame]
Eric Paris8faf23d2011-08-03 14:02:37 -04001/* Workaround for http://bugs.python.org/issue4835 */
2#ifndef SIZEOF_SOCKET_T
3#define SIZEOF_SOCKET_T SIZEOF_INT
4#endif
5
Joshua Brindle13cd4c82008-08-19 15:30:36 -04006#include <Python.h>
7#include <unistd.h>
8#include <stdlib.h>
9#include <ctype.h>
10#include <errno.h>
11#include <getopt.h>
12#include <limits.h>
13#include <sepol/sepol.h>
14#include <sepol/policydb.h>
15#include <sepol/policydb/services.h>
16#include <selinux/selinux.h>
17
18#define UNKNOWN -1
19#define BADSCON -2
20#define BADTCON -3
21#define BADTCLASS -4
22#define BADPERM -5
23#define BADCOMPUTE -6
24#define NOPOLICY -7
25#define ALLOW 0
26#define DONTAUDIT 1
27#define TERULE 2
28#define BOOLEAN 3
29#define CONSTRAINT 4
30#define RBAC 5
31
32struct boolean_t {
33 char *name;
34 int active;
35};
36
37static struct boolean_t **boollist = NULL;
38static int boolcnt = 0;
39
40struct avc_t {
41 sepol_handle_t *handle;
42 sepol_policydb_t *policydb;
43 sepol_security_id_t ssid;
44 sepol_security_id_t tsid;
45 sepol_security_class_t tclass;
46 sepol_access_vector_t av;
47};
48
49static struct avc_t *avc = NULL;
50
51static sidtab_t sidtab;
52
53static int load_booleans(const sepol_bool_t * boolean,
54 void *arg __attribute__ ((__unused__)))
55{
56 boollist[boolcnt] = malloc(sizeof(struct boolean_t));
57 boollist[boolcnt]->name = strdup(sepol_bool_get_name(boolean));
58 boollist[boolcnt]->active = sepol_bool_get_value(boolean);
59 boolcnt++;
60 return 0;
61}
62
63static int check_booleans(struct boolean_t **bools)
64{
65 char errormsg[PATH_MAX];
66 struct sepol_av_decision avd;
67 unsigned int reason;
68 int rc;
69 int i;
70 sepol_bool_key_t *key = NULL;
71 sepol_bool_t *boolean = NULL;
72 int fcnt = 0;
73 int *foundlist = calloc(boolcnt, sizeof(int));
74 if (!foundlist) {
75 PyErr_SetString( PyExc_MemoryError, "Out of memory\n");
76 return fcnt;
77 }
78 for (i = 0; i < boolcnt; i++) {
79 char *name = boollist[i]->name;
80 int active = boollist[i]->active;
81 rc = sepol_bool_key_create(avc->handle, name, &key);
82 if (rc < 0) {
83 PyErr_SetString( PyExc_RuntimeError,
84 "Could not create boolean key.\n");
85 break;
86 }
87 rc = sepol_bool_query(avc->handle,
88 avc->policydb,
89 key, &boolean);
90
91 if (rc < 0) {
92 snprintf(errormsg, sizeof(errormsg),
93 "Could not find boolean %s.\n", name);
94 PyErr_SetString( PyExc_RuntimeError, errormsg);
95 break;
96 }
97
98 sepol_bool_set_value(boolean, !active);
99
100 rc = sepol_bool_set(avc->handle,
101 avc->policydb,
102 key, boolean);
103 if (rc < 0) {
104 snprintf(errormsg, sizeof(errormsg),
105 "Could not set boolean data %s.\n", name);
106 PyErr_SetString( PyExc_RuntimeError, errormsg);
107 break;
108 }
109
110 /* Reproduce the computation. */
111 rc = sepol_compute_av_reason(avc->ssid, avc->tsid, avc->tclass,
112 avc->av, &avd, &reason);
113 if (rc < 0) {
114 snprintf(errormsg, sizeof(errormsg),
115 "Error during access vector computation, skipping...");
116 PyErr_SetString( PyExc_RuntimeError, errormsg);
117
118 sepol_bool_free(boolean);
119 break;
120 } else {
121 if (!reason) {
122 foundlist[fcnt] = i;
123 fcnt++;
124 }
125 sepol_bool_set_value(boolean, active);
126 rc = sepol_bool_set(avc->handle,
127 avc->policydb, key,
128 boolean);
129 if (rc < 0) {
130 snprintf(errormsg, sizeof(errormsg),
131 "Could not set boolean data %s.\n",
132 name);
133
134 PyErr_SetString( PyExc_RuntimeError, errormsg);
135 break;
136 }
137 }
138 sepol_bool_free(boolean);
139 sepol_bool_key_free(key);
140 key = NULL;
141 boolean = NULL;
142 }
143 if (key)
144 sepol_bool_key_free(key);
145
146 if (boolean)
147 sepol_bool_free(boolean);
148
149 if (fcnt > 0) {
150 *bools = calloc(sizeof(struct boolean_t), fcnt + 1);
151 struct boolean_t *b = *bools;
152 for (i = 0; i < fcnt; i++) {
153 int ctr = foundlist[i];
154 b[i].name = strdup(boollist[ctr]->name);
155 b[i].active = !boollist[ctr]->active;
156 }
157 }
158 free(foundlist);
159 return fcnt;
160}
161
162static PyObject *finish(PyObject *self __attribute__((unused)), PyObject *args) {
163 PyObject *result = 0;
164
165 if (PyArg_ParseTuple(args,(char *)":finish")) {
166 int i = 0;
rhatdan019e6fd2012-10-15 15:25:31 -0400167 if (! avc)
168 Py_RETURN_NONE;
169
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400170 for (i = 0; i < boolcnt; i++) {
171 free(boollist[i]->name);
172 free(boollist[i]);
173 }
174 free(boollist);
175 sepol_sidtab_shutdown(&sidtab);
176 sepol_sidtab_destroy(&sidtab);
177 sepol_policydb_free(avc->policydb);
178 sepol_handle_destroy(avc->handle);
179 free(avc);
180 avc = NULL;
181 boollist = NULL;
182 boolcnt = 0;
rhatdan019e6fd2012-10-15 15:25:31 -0400183
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400184 /* Boilerplate to return "None" */
185 Py_RETURN_NONE;
186 }
187 return result;
188}
189
190
191static int __policy_init(const char *init_path)
192{
193 FILE *fp;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400194 char path[PATH_MAX];
195 char errormsg[PATH_MAX];
196 struct sepol_policy_file *pf = NULL;
197 int rc;
198 unsigned int cnt;
199
Eric Paris933840a2012-12-04 15:23:57 -0500200 path[PATH_MAX-1] = '\0';
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400201 if (init_path) {
Eric Paris933840a2012-12-04 15:23:57 -0500202 strncpy(path, init_path, PATH_MAX-1);
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400203 fp = fopen(path, "r");
204 if (!fp) {
205 snprintf(errormsg, sizeof(errormsg),
206 "unable to open %s: %s\n",
207 path, strerror(errno));
208 PyErr_SetString( PyExc_ValueError, errormsg);
209 return 1;
210 }
211 } else {
Stephen Smalley914e5912015-02-13 10:15:34 -0500212 const char *curpolicy = selinux_current_policy_path();
213 if (!curpolicy) {
214 /* SELinux disabled, must use -p option. */
215 snprintf(errormsg, sizeof(errormsg),
216 "You must specify the -p option with the path to the policy file.\n");
217 PyErr_SetString( PyExc_ValueError, errormsg);
218 return 1;
219 }
220 fp = fopen(curpolicy, "r");
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400221 if (!fp) {
222 snprintf(errormsg, sizeof(errormsg),
Dan Walsh7eec00a2013-10-09 16:18:15 -0400223 "unable to open %s: %s\n",
Stephen Smalley914e5912015-02-13 10:15:34 -0500224 curpolicy,
Dan Walsh7eec00a2013-10-09 16:18:15 -0400225 strerror(errno));
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400226 PyErr_SetString( PyExc_ValueError, errormsg);
227 return 1;
228 }
229 }
230
231 avc = calloc(sizeof(struct avc_t), 1);
232 if (!avc) {
233 PyErr_SetString( PyExc_MemoryError, "Out of memory\n");
Dan Walsh74a9a522011-10-27 10:00:21 -0400234 fclose(fp);
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400235 return 1;
236 }
237
238 /* Set up a policydb directly so that we can mutate it later
239 for testing what booleans might have allowed the access.
240 Otherwise, we'd just use sepol_set_policydb_from_file() here. */
241 if (sepol_policy_file_create(&pf) ||
242 sepol_policydb_create(&avc->policydb)) {
243 snprintf(errormsg, sizeof(errormsg),
244 "policydb_init failed: %s\n", strerror(errno));
245 PyErr_SetString( PyExc_RuntimeError, errormsg);
246 fclose(fp);
247 return 1;
248 }
249 sepol_policy_file_set_fp(pf, fp);
250 if (sepol_policydb_read(avc->policydb, pf)) {
251 snprintf(errormsg, sizeof(errormsg),
252 "invalid binary policy %s\n", path);
253 PyErr_SetString( PyExc_ValueError, errormsg);
254 fclose(fp);
255 return 1;
256 }
257 fclose(fp);
258 sepol_set_policydb(&avc->policydb->p);
259 avc->handle = sepol_handle_create();
Eric Paris802369f2011-07-05 00:27:41 -0400260 /* Turn off messages */
261 sepol_msg_set_callback(avc->handle, NULL, NULL);
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400262
263 rc = sepol_bool_count(avc->handle,
264 avc->policydb, &cnt);
265 if (rc < 0) {
266 PyErr_SetString( PyExc_RuntimeError, "unable to get bool count\n");
267 return 1;
268 }
269
Eric Parisaa62cd62012-11-29 09:41:38 -0500270 boollist = calloc(cnt, sizeof(*boollist));
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400271 if (!boollist) {
272 PyErr_SetString( PyExc_MemoryError, "Out of memory\n");
273 return 1;
274 }
275
276 sepol_bool_iterate(avc->handle, avc->policydb,
277 load_booleans, (void *)NULL);
278
279 /* Initialize the sidtab for subsequent use by sepol_context_to_sid
280 and sepol_compute_av_reason. */
281 rc = sepol_sidtab_init(&sidtab);
282 if (rc < 0) {
283 PyErr_SetString( PyExc_RuntimeError, "unable to init sidtab\n");
284 free(boollist);
285 return 1;
286 }
287 sepol_set_sidtab(&sidtab);
288 return 0;
289}
290
291static PyObject *init(PyObject *self __attribute__((unused)), PyObject *args) {
292 int result;
293 char *init_path=NULL;
Eric Parisd09bcb72012-11-19 12:42:38 -0500294 if (avc) {
295 PyErr_SetString( PyExc_RuntimeError, "init called multiple times");
296 return NULL;
297 }
Eric Paris2ea80c22011-06-29 00:29:21 -0400298 if (!PyArg_ParseTuple(args,(char *)"|s:policy_init",&init_path))
299 return NULL;
300 result = __policy_init(init_path);
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400301 return Py_BuildValue("i", result);
302}
303
304#define RETURN(X) \
Dan Walsh756013e2013-10-09 15:11:05 -0400305 { \
306 return Py_BuildValue("iO", (X), Py_None); \
307 }
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400308
309static PyObject *analyze(PyObject *self __attribute__((unused)) , PyObject *args) {
Dan Walsh6d0f1112013-10-28 10:09:55 -0400310 char *reason_buf = NULL;
Stephen Smalley9eb9c932014-02-19 09:16:17 -0500311 char * scon;
312 char * tcon;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400313 char *tclassstr;
314 PyObject *listObj;
315 PyObject *strObj;
316 int numlines;
317 struct boolean_t *bools;
318 unsigned int reason;
319 sepol_security_id_t ssid, tsid;
320 sepol_security_class_t tclass;
321 sepol_access_vector_t perm, av;
322 struct sepol_av_decision avd;
323 int rc;
324 int i=0;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400325
326 if (!PyArg_ParseTuple(args,(char *)"sssO!:audit2why",&scon,&tcon,&tclassstr,&PyList_Type, &listObj))
327 return NULL;
328
329 /* get the number of lines passed to us */
330 numlines = PyList_Size(listObj);
331
332 /* should raise an error here. */
333 if (numlines < 0) return NULL; /* Not a list */
334
Dan Walsh756013e2013-10-09 15:11:05 -0400335 if (!avc)
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400336 RETURN(NOPOLICY)
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400337
338 rc = sepol_context_to_sid(scon, strlen(scon) + 1, &ssid);
Dan Walsh756013e2013-10-09 15:11:05 -0400339 if (rc < 0)
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400340 RETURN(BADSCON)
Dan Walsh756013e2013-10-09 15:11:05 -0400341
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400342 rc = sepol_context_to_sid(tcon, strlen(tcon) + 1, &tsid);
Dan Walsh756013e2013-10-09 15:11:05 -0400343 if (rc < 0)
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400344 RETURN(BADTCON)
Dan Walsh756013e2013-10-09 15:11:05 -0400345
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400346 tclass = string_to_security_class(tclassstr);
Dan Walsh756013e2013-10-09 15:11:05 -0400347 if (!tclass)
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400348 RETURN(BADTCLASS)
Dan Walsh756013e2013-10-09 15:11:05 -0400349
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400350 /* Convert the permission list to an AV. */
351 av = 0;
352
353 /* iterate over items of the list, grabbing strings, and parsing
354 for numbers */
355 for (i=0; i<numlines; i++){
356 char *permstr;
357
358 /* grab the string object from the next element of the list */
359 strObj = PyList_GetItem(listObj, i); /* Can't fail */
360
361 /* make it a string */
Daniel J Walsh874bac82011-06-24 16:43:11 -0400362#if PY_MAJOR_VERSION >= 3
363 permstr = _PyUnicode_AsString( strObj );
364#else
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400365 permstr = PyString_AsString( strObj );
Daniel J Walsh874bac82011-06-24 16:43:11 -0400366#endif
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400367
368 perm = string_to_av_perm(tclass, permstr);
Dan Walsh756013e2013-10-09 15:11:05 -0400369 if (!perm)
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400370 RETURN(BADPERM)
Dan Walsh756013e2013-10-09 15:11:05 -0400371
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400372 av |= perm;
373 }
374
375 /* Reproduce the computation. */
Dan Walsh6d0f1112013-10-28 10:09:55 -0400376 rc = sepol_compute_av_reason_buffer(ssid, tsid, tclass, av, &avd, &reason, &reason_buf, 0);
Dan Walsh756013e2013-10-09 15:11:05 -0400377 if (rc < 0)
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400378 RETURN(BADCOMPUTE)
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400379
Dan Walsh756013e2013-10-09 15:11:05 -0400380 if (!reason)
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400381 RETURN(ALLOW)
Dan Walsh756013e2013-10-09 15:11:05 -0400382
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400383 if (reason & SEPOL_COMPUTEAV_TE) {
384 avc->ssid = ssid;
385 avc->tsid = tsid;
386 avc->tclass = tclass;
387 avc->av = av;
388 if (check_booleans(&bools) == 0) {
389 if (av & ~avd.auditdeny) {
390 RETURN(DONTAUDIT)
391 } else {
392 RETURN(TERULE)
393 }
394 } else {
Dan Walsh756013e2013-10-09 15:11:05 -0400395 PyObject *outboollist;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400396 struct boolean_t *b = bools;
397 int len=0;
398 while (b->name) {
399 len++; b++;
400 }
401 b = bools;
Dan Walsh756013e2013-10-09 15:11:05 -0400402 outboollist = PyList_New(len);
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400403 len=0;
404 while(b->name) {
Dan Walsh756013e2013-10-09 15:11:05 -0400405 PyObject *bool_ = Py_BuildValue("(si)", b->name, b->active);
406 PyList_SetItem(outboollist, len++, bool_);
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400407 b++;
408 }
409 free(bools);
Dan Walsh756013e2013-10-09 15:11:05 -0400410 /* 'N' steals the reference to outboollist */
411 return Py_BuildValue("iN", BOOLEAN, outboollist);
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400412 }
413 }
414
415 if (reason & SEPOL_COMPUTEAV_CONS) {
Dan Walsh6d0f1112013-10-28 10:09:55 -0400416 if (reason_buf) {
417 PyObject *result = NULL;
418 result = Py_BuildValue("is", CONSTRAINT, reason_buf);
419 free(reason_buf);
420 return result;
421 }
Dan Walsh756013e2013-10-09 15:11:05 -0400422 RETURN(CONSTRAINT)
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400423 }
424
Dan Walsh7504bbd2012-11-21 14:25:17 -0500425 if (reason & SEPOL_COMPUTEAV_RBAC)
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400426 RETURN(RBAC)
Dan Walsh7504bbd2012-11-21 14:25:17 -0500427
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400428 RETURN(BADCOMPUTE)
429}
430
431static PyMethodDef audit2whyMethods[] = {
432 {"init", init, METH_VARARGS,
433 "Initialize policy database."},
434 {"analyze", analyze, METH_VARARGS,
435 "Analyze AVC."},
436 {"finish", finish, METH_VARARGS,
437 "Finish using policy, free memory."},
438 {NULL, NULL, 0, NULL} /* Sentinel */
439};
440
Daniel J Walsh874bac82011-06-24 16:43:11 -0400441#if PY_MAJOR_VERSION >= 3
442/* Module-initialization logic specific to Python 3 */
443struct module_state {
444 /* empty for now */
445};
446static struct PyModuleDef moduledef = {
447 PyModuleDef_HEAD_INIT,
448 "audit2why",
449 NULL,
450 sizeof(struct module_state),
451 audit2whyMethods,
452 NULL,
453 NULL,
454 NULL,
455 NULL
456};
457
Eric Paris9b3055a2012-04-19 15:09:56 -0400458PyMODINIT_FUNC PyInit_audit2why(void); /* silence -Wmissing-prototypes */
459PyMODINIT_FUNC PyInit_audit2why(void)
Daniel J Walsh874bac82011-06-24 16:43:11 -0400460#else
Eric Paris9b3055a2012-04-19 15:09:56 -0400461PyMODINIT_FUNC initaudit2why(void); /* silence -Wmissing-prototypes */
462PyMODINIT_FUNC initaudit2why(void)
Daniel J Walsh874bac82011-06-24 16:43:11 -0400463#endif
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400464{
Daniel J Walsh874bac82011-06-24 16:43:11 -0400465 PyObject *m;
466#if PY_MAJOR_VERSION >= 3
467 m = PyModule_Create(&moduledef);
468 if (m == NULL) {
469 return NULL;
470 }
471#else
472 m = Py_InitModule("audit2why", audit2whyMethods);
473#endif
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400474 PyModule_AddIntConstant(m,"UNKNOWN", UNKNOWN);
475 PyModule_AddIntConstant(m,"BADSCON", BADSCON);
476 PyModule_AddIntConstant(m,"BADTCON", BADTCON);
477 PyModule_AddIntConstant(m,"BADTCLASS", BADTCLASS);
478 PyModule_AddIntConstant(m,"BADPERM", BADPERM);
479 PyModule_AddIntConstant(m,"BADCOMPUTE", BADCOMPUTE);
480 PyModule_AddIntConstant(m,"NOPOLICY", NOPOLICY);
481 PyModule_AddIntConstant(m,"ALLOW", ALLOW);
482 PyModule_AddIntConstant(m,"DONTAUDIT", DONTAUDIT);
483 PyModule_AddIntConstant(m,"TERULE", TERULE);
484 PyModule_AddIntConstant(m,"BOOLEAN", BOOLEAN);
485 PyModule_AddIntConstant(m,"CONSTRAINT", CONSTRAINT);
486 PyModule_AddIntConstant(m,"RBAC", RBAC);
Daniel J Walsh874bac82011-06-24 16:43:11 -0400487
488#if PY_MAJOR_VERSION >= 3
489 return m;
490#endif
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400491}