Home | History | Annotate | Download | only in src
      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 
     33 struct boolean_t {
     34 	char *name;
     35 	int active;
     36 };
     37 
     38 static struct boolean_t **boollist = NULL;
     39 static int boolcnt = 0;
     40 
     41 struct 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 
     50 static struct avc_t *avc = NULL;
     51 
     52 static sidtab_t sidtab;
     53 
     54 static 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 
     64 static 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 
    163 static 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 
    192 static int __policy_init(const char *init_path)
    193 {
    194 	FILE *fp;
    195 	char path[PATH_MAX];
    196 	char errormsg[PATH_MAX];
    197 	struct sepol_policy_file *pf = NULL;
    198 	int rc;
    199 	unsigned int cnt;
    200 
    201 	path[PATH_MAX-1] = '\0';
    202 	if (init_path) {
    203 		strncpy(path, init_path, PATH_MAX-1);
    204 		fp = fopen(path, "re");
    205 		if (!fp) {
    206 			snprintf(errormsg, sizeof(errormsg),
    207 				 "unable to open %s:  %s\n",
    208 				 path, strerror(errno));
    209 			PyErr_SetString( PyExc_ValueError, errormsg);
    210 			return 1;
    211 		}
    212 	} else {
    213 		const char *curpolicy = selinux_current_policy_path();
    214 		if (!curpolicy) {
    215 			/* SELinux disabled, must use -p option. */
    216 			snprintf(errormsg, sizeof(errormsg),
    217 				 "You must specify the -p option with the path to the policy file.\n");
    218 			PyErr_SetString( PyExc_ValueError, errormsg);
    219 			return 1;
    220 		}
    221 		fp = fopen(curpolicy, "re");
    222 		if (!fp) {
    223 			snprintf(errormsg, sizeof(errormsg),
    224 				 "unable to open %s:  %s\n",
    225 				 curpolicy,
    226 				 strerror(errno));
    227 			PyErr_SetString( PyExc_ValueError, errormsg);
    228 			return 1;
    229 		}
    230 	}
    231 
    232 	avc = calloc(sizeof(struct avc_t), 1);
    233 	if (!avc) {
    234 		PyErr_SetString( PyExc_MemoryError, "Out of memory\n");
    235 		fclose(fp);
    236 		return 1;
    237 	}
    238 
    239 	/* Set up a policydb directly so that we can mutate it later
    240 	   for testing what booleans might have allowed the access.
    241 	   Otherwise, we'd just use sepol_set_policydb_from_file() here. */
    242 	if (sepol_policy_file_create(&pf) ||
    243 	    sepol_policydb_create(&avc->policydb)) {
    244 		snprintf(errormsg, sizeof(errormsg),
    245 			 "policydb_init failed: %s\n", strerror(errno));
    246 		PyErr_SetString( PyExc_RuntimeError, errormsg);
    247 		fclose(fp);
    248 		return 1;
    249 	}
    250 	sepol_policy_file_set_fp(pf, fp);
    251 	if (sepol_policydb_read(avc->policydb, pf)) {
    252 		snprintf(errormsg, sizeof(errormsg),
    253 			 "invalid binary policy %s\n", path);
    254 		PyErr_SetString( PyExc_ValueError, errormsg);
    255 		fclose(fp);
    256 		return 1;
    257 	}
    258 	fclose(fp);
    259 	sepol_set_policydb(&avc->policydb->p);
    260 	avc->handle = sepol_handle_create();
    261 	/* Turn off messages */
    262 	sepol_msg_set_callback(avc->handle, NULL, NULL);
    263 
    264 	rc = sepol_bool_count(avc->handle,
    265 			      avc->policydb, &cnt);
    266 	if (rc < 0) {
    267 		PyErr_SetString( PyExc_RuntimeError, "unable to get bool count\n");
    268 		return 1;
    269 	}
    270 
    271 	boollist = calloc(cnt, sizeof(*boollist));
    272 	if (!boollist) {
    273 		PyErr_SetString( PyExc_MemoryError, "Out of memory\n");
    274 		return 1;
    275 	}
    276 
    277 	sepol_bool_iterate(avc->handle, avc->policydb,
    278 			   load_booleans, (void *)NULL);
    279 
    280 	/* Initialize the sidtab for subsequent use by sepol_context_to_sid
    281 	   and sepol_compute_av_reason. */
    282 	rc = sepol_sidtab_init(&sidtab);
    283 	if (rc < 0) {
    284 		PyErr_SetString( PyExc_RuntimeError, "unable to init sidtab\n");
    285 		free(boollist);
    286 		return 1;
    287 	}
    288 	sepol_set_sidtab(&sidtab);
    289 	return 0;
    290 }
    291 
    292 static PyObject *init(PyObject *self __attribute__((unused)), PyObject *args) {
    293   int result;
    294   char *init_path=NULL;
    295   if (avc) {
    296 	  PyErr_SetString( PyExc_RuntimeError, "init called multiple times");
    297 	  return NULL;
    298   }
    299   if (!PyArg_ParseTuple(args,(char *)"|s:policy_init",&init_path))
    300     return NULL;
    301   result = __policy_init(init_path);
    302   return Py_BuildValue("i", result);
    303 }
    304 
    305 #define RETURN(X) \
    306 	{ \
    307 		return Py_BuildValue("iO", (X), Py_None);	\
    308 	}
    309 
    310 static PyObject *analyze(PyObject *self __attribute__((unused)) , PyObject *args) {
    311 	char *reason_buf = NULL;
    312 	char * scon;
    313 	char * tcon;
    314 	char *tclassstr;
    315 	PyObject *listObj;
    316 	PyObject *strObj;
    317 	int numlines;
    318 	struct boolean_t *bools;
    319 	unsigned int reason;
    320 	sepol_security_id_t ssid, tsid;
    321 	sepol_security_class_t tclass;
    322 	sepol_access_vector_t perm, av;
    323 	struct sepol_av_decision avd;
    324 	int rc;
    325 	int i=0;
    326 
    327 	if (!PyArg_ParseTuple(args,(char *)"sssO!:audit2why",&scon,&tcon,&tclassstr,&PyList_Type, &listObj))
    328 		return NULL;
    329 
    330 	/* get the number of lines passed to us */
    331 	numlines = PyList_Size(listObj);
    332 
    333 	/* should raise an error here. */
    334 	if (numlines < 0)	return NULL; /* Not a list */
    335 
    336 	if (!avc)
    337 		RETURN(NOPOLICY)
    338 
    339 	rc = sepol_context_to_sid(scon, strlen(scon) + 1, &ssid);
    340 	if (rc < 0)
    341 		RETURN(BADSCON)
    342 
    343 	rc = sepol_context_to_sid(tcon, strlen(tcon) + 1, &tsid);
    344 	if (rc < 0)
    345 		RETURN(BADTCON)
    346 
    347 	rc = sepol_string_to_security_class(tclassstr, &tclass);
    348 	if (rc < 0)
    349 		RETURN(BADTCLASS)
    350 
    351 	/* Convert the permission list to an AV. */
    352 	av = 0;
    353 
    354 	/* iterate over items of the list, grabbing strings, and parsing
    355 	   for numbers */
    356 	for (i=0; i<numlines; i++){
    357 		char *permstr;
    358 
    359 		/* grab the string object from the next element of the list */
    360 		strObj = PyList_GetItem(listObj, i); /* Can't fail */
    361 
    362 		/* make it a string */
    363 #if PY_MAJOR_VERSION >= 3
    364 		permstr = _PyUnicode_AsString( strObj );
    365 #else
    366 		permstr = PyString_AsString( strObj );
    367 #endif
    368 
    369 		rc = sepol_string_to_av_perm(tclass, permstr, &perm);
    370 		if (rc < 0)
    371 			RETURN(BADPERM)
    372 
    373 		av |= perm;
    374 	}
    375 
    376 	/* Reproduce the computation. */
    377 	rc = sepol_compute_av_reason_buffer(ssid, tsid, tclass, av, &avd, &reason, &reason_buf, 0);
    378 	if (rc < 0)
    379 		RETURN(BADCOMPUTE)
    380 
    381 	if (!reason)
    382 		RETURN(ALLOW)
    383 
    384 	if (reason & SEPOL_COMPUTEAV_TE) {
    385 		avc->ssid = ssid;
    386 		avc->tsid = tsid;
    387 		avc->tclass = tclass;
    388 		avc->av = av;
    389 		if (check_booleans(&bools) == 0) {
    390 			if (av & ~avd.auditdeny) {
    391 				RETURN(DONTAUDIT)
    392 			} else {
    393 				RETURN(TERULE)
    394 			}
    395 		} else {
    396 			PyObject *outboollist;
    397 			struct boolean_t *b = bools;
    398 			int len=0;
    399 			while (b->name) {
    400 				len++; b++;
    401 			}
    402 			b = bools;
    403 			outboollist = PyList_New(len);
    404 			len=0;
    405 			while(b->name) {
    406 				PyObject *bool_ = Py_BuildValue("(si)", b->name, b->active);
    407 				PyList_SetItem(outboollist, len++, bool_);
    408 				b++;
    409 			}
    410 			free(bools);
    411 			/* 'N' steals the reference to outboollist */
    412 			return Py_BuildValue("iN", BOOLEAN, outboollist);
    413 		}
    414 	}
    415 
    416 	if (reason & SEPOL_COMPUTEAV_CONS) {
    417 		if (reason_buf) {
    418 			PyObject *result = NULL;
    419 			result = Py_BuildValue("is", CONSTRAINT, reason_buf);
    420 			free(reason_buf);
    421 			return result;
    422 		}
    423 		RETURN(CONSTRAINT)
    424 	}
    425 
    426 	if (reason & SEPOL_COMPUTEAV_RBAC)
    427 		RETURN(RBAC)
    428 
    429 	if (reason & SEPOL_COMPUTEAV_BOUNDS)
    430 		RETURN(BOUNDS)
    431 
    432         RETURN(BADCOMPUTE)
    433 }
    434 
    435 static PyMethodDef audit2whyMethods[] = {
    436     {"init",  init, METH_VARARGS,
    437      "Initialize policy database."},
    438     {"analyze",  analyze, METH_VARARGS,
    439      "Analyze AVC."},
    440     {"finish",  finish, METH_VARARGS,
    441      "Finish using policy, free memory."},
    442     {NULL, NULL, 0, NULL}        /* Sentinel */
    443 };
    444 
    445 #if PY_MAJOR_VERSION >= 3
    446 /* Module-initialization logic specific to Python 3 */
    447 static struct PyModuleDef moduledef = {
    448 	PyModuleDef_HEAD_INIT,
    449 	"audit2why",
    450 	NULL,
    451 	0,
    452 	audit2whyMethods,
    453 	NULL,
    454 	NULL,
    455 	NULL,
    456 	NULL
    457 };
    458 
    459 PyMODINIT_FUNC PyInit_audit2why(void); /* silence -Wmissing-prototypes */
    460 PyMODINIT_FUNC PyInit_audit2why(void)
    461 #else
    462 PyMODINIT_FUNC initaudit2why(void); /* silence -Wmissing-prototypes */
    463 PyMODINIT_FUNC initaudit2why(void)
    464 #endif
    465 {
    466 	PyObject *m;
    467 #if PY_MAJOR_VERSION >= 3
    468 	m = PyModule_Create(&moduledef);
    469 	if (m == NULL) {
    470 		return NULL;
    471 	}
    472 #else
    473 	m  = Py_InitModule("audit2why", audit2whyMethods);
    474 #endif
    475 	PyModule_AddIntConstant(m,"UNKNOWN", UNKNOWN);
    476 	PyModule_AddIntConstant(m,"BADSCON", BADSCON);
    477 	PyModule_AddIntConstant(m,"BADTCON", BADTCON);
    478 	PyModule_AddIntConstant(m,"BADTCLASS", BADTCLASS);
    479 	PyModule_AddIntConstant(m,"BADPERM", BADPERM);
    480 	PyModule_AddIntConstant(m,"BADCOMPUTE", BADCOMPUTE);
    481 	PyModule_AddIntConstant(m,"NOPOLICY", NOPOLICY);
    482 	PyModule_AddIntConstant(m,"ALLOW", ALLOW);
    483 	PyModule_AddIntConstant(m,"DONTAUDIT", DONTAUDIT);
    484 	PyModule_AddIntConstant(m,"TERULE", TERULE);
    485 	PyModule_AddIntConstant(m,"BOOLEAN", BOOLEAN);
    486 	PyModule_AddIntConstant(m,"CONSTRAINT", CONSTRAINT);
    487 	PyModule_AddIntConstant(m,"RBAC", RBAC);
    488 	PyModule_AddIntConstant(m,"BOUNDS", BOUNDS);
    489 
    490 #if PY_MAJOR_VERSION >= 3
    491 	return m;
    492 #endif
    493 }
    494