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 
     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