1/* Workaround for http://bugs.python.org/issue4835 */ 2#ifndef SIZEOF_SOCKET_T 3#define SIZEOF_SOCKET_T SIZEOF_INT 4#endif 5 6#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#define BOUNDS 6 32 33struct boolean_t { 34 char *name; 35 int active; 36}; 37 38static struct boolean_t **boollist = NULL; 39static int boolcnt = 0; 40 41struct avc_t { 42 sepol_handle_t *handle; 43 sepol_policydb_t *policydb; 44 sepol_security_id_t ssid; 45 sepol_security_id_t tsid; 46 sepol_security_class_t tclass; 47 sepol_access_vector_t av; 48}; 49 50static struct avc_t *avc = NULL; 51 52static sidtab_t sidtab; 53 54static int load_booleans(const sepol_bool_t * boolean, 55 void *arg __attribute__ ((__unused__))) 56{ 57 boollist[boolcnt] = malloc(sizeof(struct boolean_t)); 58 boollist[boolcnt]->name = strdup(sepol_bool_get_name(boolean)); 59 boollist[boolcnt]->active = sepol_bool_get_value(boolean); 60 boolcnt++; 61 return 0; 62} 63 64static int check_booleans(struct boolean_t **bools) 65{ 66 char errormsg[PATH_MAX]; 67 struct sepol_av_decision avd; 68 unsigned int reason; 69 int rc; 70 int i; 71 sepol_bool_key_t *key = NULL; 72 sepol_bool_t *boolean = NULL; 73 int fcnt = 0; 74 int *foundlist = calloc(boolcnt, sizeof(int)); 75 if (!foundlist) { 76 PyErr_SetString( PyExc_MemoryError, "Out of memory\n"); 77 return fcnt; 78 } 79 for (i = 0; i < boolcnt; i++) { 80 char *name = boollist[i]->name; 81 int active = boollist[i]->active; 82 rc = sepol_bool_key_create(avc->handle, name, &key); 83 if (rc < 0) { 84 PyErr_SetString( PyExc_RuntimeError, 85 "Could not create boolean key.\n"); 86 break; 87 } 88 rc = sepol_bool_query(avc->handle, 89 avc->policydb, 90 key, &boolean); 91 92 if (rc < 0) { 93 snprintf(errormsg, sizeof(errormsg), 94 "Could not find boolean %s.\n", name); 95 PyErr_SetString( PyExc_RuntimeError, errormsg); 96 break; 97 } 98 99 sepol_bool_set_value(boolean, !active); 100 101 rc = sepol_bool_set(avc->handle, 102 avc->policydb, 103 key, boolean); 104 if (rc < 0) { 105 snprintf(errormsg, sizeof(errormsg), 106 "Could not set boolean data %s.\n", name); 107 PyErr_SetString( PyExc_RuntimeError, errormsg); 108 break; 109 } 110 111 /* Reproduce the computation. */ 112 rc = sepol_compute_av_reason(avc->ssid, avc->tsid, avc->tclass, 113 avc->av, &avd, &reason); 114 if (rc < 0) { 115 snprintf(errormsg, sizeof(errormsg), 116 "Error during access vector computation, skipping..."); 117 PyErr_SetString( PyExc_RuntimeError, errormsg); 118 119 sepol_bool_free(boolean); 120 break; 121 } else { 122 if (!reason) { 123 foundlist[fcnt] = i; 124 fcnt++; 125 } 126 sepol_bool_set_value(boolean, active); 127 rc = sepol_bool_set(avc->handle, 128 avc->policydb, key, 129 boolean); 130 if (rc < 0) { 131 snprintf(errormsg, sizeof(errormsg), 132 "Could not set boolean data %s.\n", 133 name); 134 135 PyErr_SetString( PyExc_RuntimeError, errormsg); 136 break; 137 } 138 } 139 sepol_bool_free(boolean); 140 sepol_bool_key_free(key); 141 key = NULL; 142 boolean = NULL; 143 } 144 if (key) 145 sepol_bool_key_free(key); 146 147 if (boolean) 148 sepol_bool_free(boolean); 149 150 if (fcnt > 0) { 151 *bools = calloc(sizeof(struct boolean_t), fcnt + 1); 152 struct boolean_t *b = *bools; 153 for (i = 0; i < fcnt; i++) { 154 int ctr = foundlist[i]; 155 b[i].name = strdup(boollist[ctr]->name); 156 b[i].active = !boollist[ctr]->active; 157 } 158 } 159 free(foundlist); 160 return fcnt; 161} 162 163static PyObject *finish(PyObject *self __attribute__((unused)), PyObject *args) { 164 PyObject *result = 0; 165 166 if (PyArg_ParseTuple(args,(char *)":finish")) { 167 int i = 0; 168 if (! avc) 169 Py_RETURN_NONE; 170 171 for (i = 0; i < boolcnt; i++) { 172 free(boollist[i]->name); 173 free(boollist[i]); 174 } 175 free(boollist); 176 sepol_sidtab_shutdown(&sidtab); 177 sepol_sidtab_destroy(&sidtab); 178 sepol_policydb_free(avc->policydb); 179 sepol_handle_destroy(avc->handle); 180 free(avc); 181 avc = NULL; 182 boollist = NULL; 183 boolcnt = 0; 184 185 /* Boilerplate to return "None" */ 186 Py_RETURN_NONE; 187 } 188 return result; 189} 190 191 192static int __policy_init(const char *init_path) 193{ 194 FILE *fp = NULL; 195 const char *curpolicy; 196 char errormsg[PATH_MAX+1024+20]; 197 struct sepol_policy_file *pf = NULL; 198 int rc; 199 unsigned int cnt; 200 201 if (init_path) { 202 curpolicy = init_path; 203 } else { 204 curpolicy = selinux_current_policy_path(); 205 if (!curpolicy) { 206 /* SELinux disabled, must use -p option. */ 207 snprintf(errormsg, sizeof(errormsg), 208 "You must specify the -p option with the path to the policy file.\n"); 209 PyErr_SetString( PyExc_ValueError, errormsg); 210 return 1; 211 } 212 } 213 214 fp = fopen(curpolicy, "re"); 215 if (!fp) { 216 snprintf(errormsg, sizeof(errormsg), 217 "unable to open %s: %m\n", 218 curpolicy); 219 PyErr_SetString( PyExc_ValueError, errormsg); 220 return 1; 221 } 222 223 avc = calloc(sizeof(struct avc_t), 1); 224 if (!avc) { 225 PyErr_SetString( PyExc_MemoryError, "Out of memory\n"); 226 fclose(fp); 227 return 1; 228 } 229 230 /* Set up a policydb directly so that we can mutate it later 231 for testing what booleans might have allowed the access. 232 Otherwise, we'd just use sepol_set_policydb_from_file() here. */ 233 if (sepol_policy_file_create(&pf) || 234 sepol_policydb_create(&avc->policydb)) { 235 snprintf(errormsg, sizeof(errormsg), 236 "policydb_init failed: %m\n"); 237 PyErr_SetString( PyExc_RuntimeError, errormsg); 238 goto err; 239 } 240 sepol_policy_file_set_fp(pf, fp); 241 if (sepol_policydb_read(avc->policydb, pf)) { 242 snprintf(errormsg, sizeof(errormsg), 243 "invalid binary policy %s\n", curpolicy); 244 PyErr_SetString( PyExc_ValueError, errormsg); 245 goto err; 246 } 247 fclose(fp); 248 fp = NULL; 249 sepol_set_policydb(&avc->policydb->p); 250 avc->handle = sepol_handle_create(); 251 /* Turn off messages */ 252 sepol_msg_set_callback(avc->handle, NULL, NULL); 253 254 rc = sepol_bool_count(avc->handle, 255 avc->policydb, &cnt); 256 if (rc < 0) { 257 PyErr_SetString( PyExc_RuntimeError, "unable to get bool count\n"); 258 goto err; 259 } 260 261 boollist = calloc(cnt, sizeof(*boollist)); 262 if (!boollist) { 263 PyErr_SetString( PyExc_MemoryError, "Out of memory\n"); 264 goto err; 265 } 266 267 sepol_bool_iterate(avc->handle, avc->policydb, 268 load_booleans, NULL); 269 270 /* Initialize the sidtab for subsequent use by sepol_context_to_sid 271 and sepol_compute_av_reason. */ 272 rc = sepol_sidtab_init(&sidtab); 273 if (rc < 0) { 274 PyErr_SetString( PyExc_RuntimeError, "unable to init sidtab\n"); 275 goto err; 276 } 277 sepol_set_sidtab(&sidtab); 278 return 0; 279 280err: 281 if (boollist) 282 free(boollist); 283 if (avc){ 284 if (avc->handle) 285 sepol_handle_destroy(avc->handle); 286 if (avc->policydb) 287 sepol_policydb_free(avc->policydb); 288 free(avc); 289 } 290 if (pf) 291 sepol_policy_file_free(pf); 292 if (fp) 293 fclose(fp); 294 return 1; 295} 296 297static PyObject *init(PyObject *self __attribute__((unused)), PyObject *args) { 298 int result; 299 char *init_path = NULL; 300 if (avc) { 301 PyErr_SetString( PyExc_RuntimeError, "init called multiple times"); 302 return NULL; 303 } 304 if (!PyArg_ParseTuple(args,(char *)"|s:policy_init",&init_path)) 305 return NULL; 306 result = __policy_init(init_path); 307 return Py_BuildValue("i", result); 308} 309 310#define RETURN(X) \ 311 { \ 312 return Py_BuildValue("iO", (X), Py_None); \ 313 } 314 315static PyObject *analyze(PyObject *self __attribute__((unused)) , PyObject *args) { 316 char *reason_buf = NULL; 317 char * scon; 318 char * tcon; 319 char *tclassstr; 320 PyObject *listObj; 321 PyObject *strObj; 322 int numlines; 323 struct boolean_t *bools; 324 unsigned int reason; 325 sepol_security_id_t ssid, tsid; 326 sepol_security_class_t tclass; 327 sepol_access_vector_t perm, av; 328 struct sepol_av_decision avd; 329 int rc; 330 int i = 0; 331 332 if (!PyArg_ParseTuple(args,(char *)"sssO!:audit2why",&scon,&tcon,&tclassstr,&PyList_Type, &listObj)) 333 return NULL; 334 335 /* get the number of lines passed to us */ 336 numlines = PyList_Size(listObj); 337 338 /* should raise an error here. */ 339 if (numlines < 0) return NULL; /* Not a list */ 340 341 if (!avc) 342 RETURN(NOPOLICY) 343 344 rc = sepol_context_to_sid(scon, strlen(scon) + 1, &ssid); 345 if (rc < 0) 346 RETURN(BADSCON) 347 348 rc = sepol_context_to_sid(tcon, strlen(tcon) + 1, &tsid); 349 if (rc < 0) 350 RETURN(BADTCON) 351 352 rc = sepol_string_to_security_class(tclassstr, &tclass); 353 if (rc < 0) 354 RETURN(BADTCLASS) 355 356 /* Convert the permission list to an AV. */ 357 av = 0; 358 359 /* iterate over items of the list, grabbing strings, and parsing 360 for numbers */ 361 for (i = 0; i < numlines; i++){ 362 const char *permstr; 363 364 /* grab the string object from the next element of the list */ 365 strObj = PyList_GetItem(listObj, i); /* Can't fail */ 366 367 /* make it a string */ 368#if PY_MAJOR_VERSION >= 3 369 permstr = _PyUnicode_AsString( strObj ); 370#else 371 permstr = PyString_AsString( strObj ); 372#endif 373 374 rc = sepol_string_to_av_perm(tclass, permstr, &perm); 375 if (rc < 0) 376 RETURN(BADPERM) 377 378 av |= perm; 379 } 380 381 /* Reproduce the computation. */ 382 rc = sepol_compute_av_reason_buffer(ssid, tsid, tclass, av, &avd, &reason, &reason_buf, 0); 383 if (rc < 0) 384 RETURN(BADCOMPUTE) 385 386 if (!reason) 387 RETURN(ALLOW) 388 389 if (reason & SEPOL_COMPUTEAV_TE) { 390 avc->ssid = ssid; 391 avc->tsid = tsid; 392 avc->tclass = tclass; 393 avc->av = av; 394 if (check_booleans(&bools) == 0) { 395 if (av & ~avd.auditdeny) { 396 RETURN(DONTAUDIT) 397 } else { 398 RETURN(TERULE) 399 } 400 } else { 401 PyObject *outboollist; 402 struct boolean_t *b = bools; 403 int len = 0; 404 while (b->name) { 405 len++; b++; 406 } 407 b = bools; 408 outboollist = PyList_New(len); 409 len = 0; 410 while(b->name) { 411 PyObject *bool_ = Py_BuildValue("(si)", b->name, b->active); 412 PyList_SetItem(outboollist, len++, bool_); 413 b++; 414 } 415 free(bools); 416 /* 'N' steals the reference to outboollist */ 417 return Py_BuildValue("iN", BOOLEAN, outboollist); 418 } 419 } 420 421 if (reason & SEPOL_COMPUTEAV_CONS) { 422 if (reason_buf) { 423 PyObject *result = NULL; 424 result = Py_BuildValue("is", CONSTRAINT, reason_buf); 425 free(reason_buf); 426 return result; 427 } 428 RETURN(CONSTRAINT) 429 } 430 431 if (reason & SEPOL_COMPUTEAV_RBAC) 432 RETURN(RBAC) 433 434 if (reason & SEPOL_COMPUTEAV_BOUNDS) 435 RETURN(BOUNDS) 436 437 RETURN(BADCOMPUTE) 438} 439 440static PyMethodDef audit2whyMethods[] = { 441 {"init", init, METH_VARARGS, 442 "Initialize policy database."}, 443 {"analyze", analyze, METH_VARARGS, 444 "Analyze AVC."}, 445 {"finish", finish, METH_VARARGS, 446 "Finish using policy, free memory."}, 447 {NULL, NULL, 0, NULL} /* Sentinel */ 448}; 449 450#if PY_MAJOR_VERSION >= 3 451/* Module-initialization logic specific to Python 3 */ 452static struct PyModuleDef moduledef = { 453 PyModuleDef_HEAD_INIT, 454 "audit2why", 455 NULL, 456 0, 457 audit2whyMethods, 458 NULL, 459 NULL, 460 NULL, 461 NULL 462}; 463 464PyMODINIT_FUNC PyInit_audit2why(void); /* silence -Wmissing-prototypes */ 465PyMODINIT_FUNC PyInit_audit2why(void) 466#else 467PyMODINIT_FUNC initaudit2why(void); /* silence -Wmissing-prototypes */ 468PyMODINIT_FUNC initaudit2why(void) 469#endif 470{ 471 PyObject *m; 472#if PY_MAJOR_VERSION >= 3 473 m = PyModule_Create(&moduledef); 474 if (m == NULL) { 475 return NULL; 476 } 477#else 478 m = Py_InitModule("audit2why", audit2whyMethods); 479#endif 480 PyModule_AddIntConstant(m,"UNKNOWN", UNKNOWN); 481 PyModule_AddIntConstant(m,"BADSCON", BADSCON); 482 PyModule_AddIntConstant(m,"BADTCON", BADTCON); 483 PyModule_AddIntConstant(m,"BADTCLASS", BADTCLASS); 484 PyModule_AddIntConstant(m,"BADPERM", BADPERM); 485 PyModule_AddIntConstant(m,"BADCOMPUTE", BADCOMPUTE); 486 PyModule_AddIntConstant(m,"NOPOLICY", NOPOLICY); 487 PyModule_AddIntConstant(m,"ALLOW", ALLOW); 488 PyModule_AddIntConstant(m,"DONTAUDIT", DONTAUDIT); 489 PyModule_AddIntConstant(m,"TERULE", TERULE); 490 PyModule_AddIntConstant(m,"BOOLEAN", BOOLEAN); 491 PyModule_AddIntConstant(m,"CONSTRAINT", CONSTRAINT); 492 PyModule_AddIntConstant(m,"RBAC", RBAC); 493 PyModule_AddIntConstant(m,"BOUNDS", BOUNDS); 494 495#if PY_MAJOR_VERSION >= 3 496 return m; 497#endif 498} 499