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 32 struct boolean_t { 33 char *name; 34 int active; 35 }; 36 37 static struct boolean_t **boollist = NULL; 38 static int boolcnt = 0; 39 40 struct 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 49 static struct avc_t *avc = NULL; 50 51 static sidtab_t sidtab; 52 53 static 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 63 static 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 162 static PyObject *finish(PyObject *self __attribute__((unused)), PyObject *args) { 163 PyObject *result = 0; 164 165 if (PyArg_ParseTuple(args,(char *)":finish")) { 166 int i = 0; 167 if (! avc) 168 Py_RETURN_NONE; 169 170 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; 183 184 /* Boilerplate to return "None" */ 185 Py_RETURN_NONE; 186 } 187 return result; 188 } 189 190 191 static int __policy_init(const char *init_path) 192 { 193 FILE *fp; 194 char path[PATH_MAX]; 195 char errormsg[PATH_MAX]; 196 struct sepol_policy_file *pf = NULL; 197 int rc; 198 unsigned int cnt; 199 200 path[PATH_MAX-1] = '\0'; 201 if (init_path) { 202 strncpy(path, init_path, PATH_MAX-1); 203 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 { 212 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"); 221 if (!fp) { 222 snprintf(errormsg, sizeof(errormsg), 223 "unable to open %s: %s\n", 224 curpolicy, 225 strerror(errno)); 226 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"); 234 fclose(fp); 235 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(); 260 /* Turn off messages */ 261 sepol_msg_set_callback(avc->handle, NULL, NULL); 262 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 270 boollist = calloc(cnt, sizeof(*boollist)); 271 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 291 static PyObject *init(PyObject *self __attribute__((unused)), PyObject *args) { 292 int result; 293 char *init_path=NULL; 294 if (avc) { 295 PyErr_SetString( PyExc_RuntimeError, "init called multiple times"); 296 return NULL; 297 } 298 if (!PyArg_ParseTuple(args,(char *)"|s:policy_init",&init_path)) 299 return NULL; 300 result = __policy_init(init_path); 301 return Py_BuildValue("i", result); 302 } 303 304 #define RETURN(X) \ 305 { \ 306 return Py_BuildValue("iO", (X), Py_None); \ 307 } 308 309 static PyObject *analyze(PyObject *self __attribute__((unused)) , PyObject *args) { 310 char *reason_buf = NULL; 311 char * scon; 312 char * tcon; 313 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; 325 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 335 if (!avc) 336 RETURN(NOPOLICY) 337 338 rc = sepol_context_to_sid(scon, strlen(scon) + 1, &ssid); 339 if (rc < 0) 340 RETURN(BADSCON) 341 342 rc = sepol_context_to_sid(tcon, strlen(tcon) + 1, &tsid); 343 if (rc < 0) 344 RETURN(BADTCON) 345 346 tclass = string_to_security_class(tclassstr); 347 if (!tclass) 348 RETURN(BADTCLASS) 349 350 /* 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 */ 362 #if PY_MAJOR_VERSION >= 3 363 permstr = _PyUnicode_AsString( strObj ); 364 #else 365 permstr = PyString_AsString( strObj ); 366 #endif 367 368 perm = string_to_av_perm(tclass, permstr); 369 if (!perm) 370 RETURN(BADPERM) 371 372 av |= perm; 373 } 374 375 /* Reproduce the computation. */ 376 rc = sepol_compute_av_reason_buffer(ssid, tsid, tclass, av, &avd, &reason, &reason_buf, 0); 377 if (rc < 0) 378 RETURN(BADCOMPUTE) 379 380 if (!reason) 381 RETURN(ALLOW) 382 383 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 { 395 PyObject *outboollist; 396 struct boolean_t *b = bools; 397 int len=0; 398 while (b->name) { 399 len++; b++; 400 } 401 b = bools; 402 outboollist = PyList_New(len); 403 len=0; 404 while(b->name) { 405 PyObject *bool_ = Py_BuildValue("(si)", b->name, b->active); 406 PyList_SetItem(outboollist, len++, bool_); 407 b++; 408 } 409 free(bools); 410 /* 'N' steals the reference to outboollist */ 411 return Py_BuildValue("iN", BOOLEAN, outboollist); 412 } 413 } 414 415 if (reason & SEPOL_COMPUTEAV_CONS) { 416 if (reason_buf) { 417 PyObject *result = NULL; 418 result = Py_BuildValue("is", CONSTRAINT, reason_buf); 419 free(reason_buf); 420 return result; 421 } 422 RETURN(CONSTRAINT) 423 } 424 425 if (reason & SEPOL_COMPUTEAV_RBAC) 426 RETURN(RBAC) 427 428 RETURN(BADCOMPUTE) 429 } 430 431 static 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 441 #if PY_MAJOR_VERSION >= 3 442 /* Module-initialization logic specific to Python 3 */ 443 struct module_state { 444 /* empty for now */ 445 }; 446 static 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 458 PyMODINIT_FUNC PyInit_audit2why(void); /* silence -Wmissing-prototypes */ 459 PyMODINIT_FUNC PyInit_audit2why(void) 460 #else 461 PyMODINIT_FUNC initaudit2why(void); /* silence -Wmissing-prototypes */ 462 PyMODINIT_FUNC initaudit2why(void) 463 #endif 464 { 465 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 474 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); 487 488 #if PY_MAJOR_VERSION >= 3 489 return m; 490 #endif 491 } 492