1/**
2 *  @file
3 *  Command line tool to search TE rules.
4 *
5 *  @author Frank Mayer  mayerf@tresys.com
6 *  @author Jeremy A. Mowery jmowery@tresys.com
7 *  @author Paul Rosenfeld  prosenfeld@tresys.com
8 *  @author Thomas Liu  <tliu@redhat.com>
9 *  @author Dan Walsh  <dwalsh@redhat.com>
10 *
11 *  Copyright (C) 2003-2008 Tresys Technology, LLC
12 *
13 *  This program is free software; you can redistribute it and/or modify
14 *  it under the terms of the GNU General Public License as published by
15 *  the Free Software Foundation; either version 2 of the License, or
16 *  (at your option) any later version.
17 *
18 *  This program is distributed in the hope that it will be useful,
19 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
20 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 *  GNU General Public License for more details.
22 *
23 *  You should have received a copy of the GNU General Public License
24 *  along with this program; if not, write to the Free Software
25 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
26 */
27
28/**
29 * This is a modified version of seinfo to be used as part of a library for
30 * Python bindings.
31 */
32
33#include "common.h"
34#include "policy.h"
35
36/* libapol */
37#include <apol/policy-query.h>
38#include <apol/render.h>
39#include <apol/util.h>
40#include <apol/vector.h>
41
42/* libqpol */
43#include <qpol/policy.h>
44#include <qpol/util.h>
45
46/* other */
47#include <errno.h>
48#include <stdlib.h>
49#include <stdio.h>
50#include <string.h>
51#include <assert.h>
52
53#define COPYRIGHT_INFO "Copyright (C) 2003-2007 Tresys Technology, LLC"
54
55enum input
56{
57	TYPE, ATTRIBUTE, ROLE, USER, PORT, BOOLEAN, CLASS, SENS, CATS
58};
59
60static int py_insert_long(PyObject *dict, const char *name, int value)
61{
62	int rt;
63	PyObject *obj = PyLong_FromLong(value);
64	if (!obj) return -1;
65	rt = PyDict_SetItemString(dict, name, obj);
66	Py_DECREF(obj);
67	return rt;
68}
69
70static int py_insert_bool(PyObject *dict, const char *name, int value)
71{
72	int rt;
73	PyObject *obj = PyBool_FromLong(value);
74	if (!obj) return -1;
75	rt = PyDict_SetItemString(dict, name, obj);
76	Py_DECREF(obj);
77	return rt;
78}
79
80/**
81 * Get a policy's MLS sensitivities.
82 * If this function is given a name, it will attempt to
83 * get statistics about a particular sensitivity; otherwise
84 * the function gets statistics about all of the policy's
85 * sensitivities.
86 *
87 * @param name Reference to a sensitivity's name; if NULL,
88 * all sensitivities will be considered
89 * @param policydb Reference to a policy
90 *
91 * @return 0 on success, < 0 on error.
92 */
93static PyObject* get_sens(const char *name, const apol_policy_t * policydb)
94{
95	PyObject *dict = NULL;
96	int error = 0;
97	int rt = 0;
98	size_t i;
99	char *tmp = NULL;
100	const char *lvl_name = NULL;
101	apol_level_query_t *query = NULL;
102	apol_vector_t *v = NULL;
103	const qpol_level_t *level = NULL;
104	apol_mls_level_t *ap_mls_lvl = NULL;
105	qpol_policy_t *q = apol_policy_get_qpol(policydb);
106
107	query = apol_level_query_create();
108	if (!query)
109		goto cleanup;
110	if (apol_level_query_set_sens(policydb, query, name))
111		goto cleanup;
112	if (apol_level_get_by_query(policydb, query, &v))
113		goto cleanup;
114
115	dict = PyDict_New();
116	if (!dict) goto err;
117	for (i = 0; i < apol_vector_get_size(v); i++) {
118		level = apol_vector_get_element(v, i);
119		if (qpol_level_get_name(q, level, &lvl_name))
120			goto err;
121		ap_mls_lvl = (apol_mls_level_t *) apol_mls_level_create_from_qpol_level_datum(policydb, level);
122		tmp = apol_mls_level_render(policydb, ap_mls_lvl);
123		apol_mls_level_destroy(&ap_mls_lvl);
124		if (!tmp)
125			goto cleanup;
126		if (py_insert_string(dict, lvl_name, tmp))
127			goto err;
128		free(tmp); tmp = NULL;
129		if (rt) goto err;
130	}
131
132	if (name && !apol_vector_get_size(v)) {
133		goto cleanup;
134	}
135
136	goto cleanup;
137err:
138	error = errno;
139	PyErr_SetString(PyExc_RuntimeError,strerror(error));
140	py_decref(dict); dict = NULL;
141cleanup:
142	free(tmp);
143	apol_level_query_destroy(&query);
144	apol_vector_destroy(&v);
145	errno = error;
146	return dict;
147}
148
149/**
150 * Compare two qpol_cat_datum_t objects.
151 * This function is meant to be passed to apol_vector_compare
152 * as the callback for performing comparisons.
153 *
154 * @param datum1 Reference to a qpol_type_datum_t object
155 * @param datum2 Reference to a qpol_type_datum_t object
156 * @param data Reference to a policy
157 * @return Greater than 0 if the first argument is less than the second argument,
158 * less than 0 if the first argument is greater than the second argument,
159 * 0 if the arguments are equal
160 */
161static int qpol_cat_datum_compare(const void *datum1, const void *datum2, void *data)
162{
163	const qpol_cat_t *cat_datum1 = NULL, *cat_datum2 = NULL;
164	apol_policy_t *policydb = NULL;
165	qpol_policy_t *q;
166	uint32_t val1, val2;
167
168	policydb = (apol_policy_t *) data;
169	q = apol_policy_get_qpol(policydb);
170	assert(policydb);
171
172	if (!datum1 || !datum2)
173		goto exit_err;
174	cat_datum1 = datum1;
175	cat_datum2 = datum2;
176
177	if (qpol_cat_get_value(q, cat_datum1, &val1))
178		goto exit_err;
179	if (qpol_cat_get_value(q, cat_datum2, &val2))
180		goto exit_err;
181
182	return (val1 > val2) ? 1 : ((val1 == val2) ? 0 : -1);
183
184      exit_err:
185	assert(0);
186	return 0;
187}
188
189/**
190 * Compare two qpol_level_datum_t objects.
191 * This function is meant to be passed to apol_vector_compare
192 * as the callback for performing comparisons.
193 *
194 * @param datum1 Reference to a qpol_level_datum_t object
195 * @param datum2 Reference to a qpol_level_datum_t object
196 * @param data Reference to a policy
197 * @return Greater than 0 if the first argument is less than the second argument,
198 * less than 0 if the first argument is greater than the second argument,
199 * 0 if the arguments are equal
200 */
201static int qpol_level_datum_compare(const void *datum1, const void *datum2, void *data)
202{
203	const qpol_level_t *lvl_datum1 = NULL, *lvl_datum2 = NULL;
204	apol_policy_t *policydb = NULL;
205	qpol_policy_t *q;
206	uint32_t val1, val2;
207
208	policydb = (apol_policy_t *) data;
209	assert(policydb);
210	q = apol_policy_get_qpol(policydb);
211
212	if (!datum1 || !datum2)
213		goto exit_err;
214	lvl_datum1 = datum1;
215	lvl_datum2 = datum2;
216
217	if (qpol_level_get_value(q, lvl_datum1, &val1))
218		goto exit_err;
219	if (qpol_level_get_value(q, lvl_datum2, &val2))
220		goto exit_err;
221
222	return (val1 > val2) ? 1 : ((val1 == val2) ? 0 : -1);
223
224      exit_err:
225	assert(0);
226	return 0;
227}
228
229/**
230 * Gets a textual representation of a MLS category and
231 * all of that category's sensitivies.
232 *
233 * @param type_datum Reference to sepol type_datum
234 * @param policydb Reference to a policy
235 */
236static PyObject* get_cat_sens(const qpol_cat_t * cat_datum, const apol_policy_t * policydb)
237{
238	const char *cat_name, *lvl_name;
239	apol_level_query_t *query = NULL;
240	apol_vector_t *v = NULL;
241	const qpol_level_t *lvl_datum = NULL;
242	qpol_policy_t *q = apol_policy_get_qpol(policydb);
243	size_t i, n_sens = 0;
244	int error = 0;
245	PyObject *list = NULL;
246	PyObject *dict = PyDict_New();
247	if (!dict) goto err;
248	if (!cat_datum || !policydb)
249		goto err;
250
251	/* get category name for apol query */
252	if (qpol_cat_get_name(q, cat_datum, &cat_name))
253		goto cleanup;
254
255	query = apol_level_query_create();
256	if (!query)
257		goto err;
258	if (apol_level_query_set_cat(policydb, query, cat_name))
259		goto err;
260	if (apol_level_get_by_query(policydb, query, &v))
261		goto err;
262	apol_vector_sort(v, &qpol_level_datum_compare, (void *)policydb);
263	dict = PyDict_New();
264	if (!dict) goto err;
265	if (py_insert_string(dict, "name", cat_name))
266		goto err;
267	n_sens = apol_vector_get_size(v);
268	list = PyList_New(0);
269	if (!list) goto err;
270	for (i = 0; i < n_sens; i++) {
271		lvl_datum = (qpol_level_t *) apol_vector_get_element(v, i);
272		if (!lvl_datum)
273			goto err;
274		if (qpol_level_get_name(q, lvl_datum, &lvl_name))
275			goto err;
276		if (py_append_string(list, lvl_name))
277			goto err;
278	}
279	if (py_insert_obj(dict, "level", list))
280		goto err;
281	Py_DECREF(list);
282
283	goto cleanup;
284err:
285	error = errno;
286	PyErr_SetString(PyExc_RuntimeError,strerror(errno));
287	py_decref(list); list = NULL;
288	py_decref(dict); dict = NULL;
289cleanup:
290	apol_level_query_destroy(&query);
291	apol_vector_destroy(&v);
292	errno = error;
293	return dict;
294}
295
296/**
297 * Prints statistics regarding a policy's MLS categories.
298 * If this function is given a name, it will attempt to
299 * get statistics about a particular category; otherwise
300 * the function gets statistics about all of the policy's
301 * categories.
302 *
303 * @param name Reference to a MLS category's name; if NULL,
304 * all categories will be considered
305 * @param policydb Reference to a policy
306 *
307 * @return 0 on success, < 0 on error.
308 */
309static PyObject* get_cats(const char *name, const apol_policy_t * policydb)
310{
311	PyObject *obj = NULL;
312	apol_cat_query_t *query = NULL;
313	apol_vector_t *v = NULL;
314	const qpol_cat_t *cat_datum = NULL;
315	size_t i, n_cats;
316	int error = 0;
317	int rt;
318	PyObject *list = PyList_New(0);
319	if (!list) goto err;
320
321	query = apol_cat_query_create();
322	if (!query)
323		goto err;
324	if (apol_cat_query_set_cat(policydb, query, name))
325		goto err;
326	if (apol_cat_get_by_query(policydb, query, &v))
327		goto err;
328	n_cats = apol_vector_get_size(v);
329	apol_vector_sort(v, &qpol_cat_datum_compare, (void *)policydb);
330
331	for (i = 0; i < n_cats; i++) {
332		cat_datum = apol_vector_get_element(v, i);
333		if (!cat_datum)
334			goto err;
335		obj = get_cat_sens(cat_datum, policydb);
336		if (!obj)
337			goto err;
338		rt = py_append_obj(list, obj);
339		Py_DECREF(obj);
340		if (rt) goto err;
341	}
342
343	if (name && !n_cats) {
344		goto err;
345	}
346
347	goto cleanup;
348err:
349	error = errno;
350	PyErr_SetString(PyExc_RuntimeError,strerror(errno));
351	py_decref(list); list = NULL;
352cleanup:
353	apol_cat_query_destroy(&query);
354	apol_vector_destroy(&v);
355	errno = error;
356	return list;
357}
358
359/**
360 * Get the alias of a type.
361 *
362 * @param type_datum Reference to sepol type_datum
363 * @param policydb Reference to a policy
364 * attributes
365 */
366static PyObject* get_type_aliases(const qpol_type_t * type_datum, const apol_policy_t * policydb)
367{
368	qpol_iterator_t *iter = NULL;
369	size_t alias_size;
370	unsigned char isattr, isalias;
371	const char *type_name = NULL;
372	const char *alias_name;
373	int error = 0;
374	qpol_policy_t *q = apol_policy_get_qpol(policydb);
375	PyObject *list = PyList_New(0);
376	if (!list) goto err;
377
378	if (qpol_type_get_name(q, type_datum, &type_name))
379		goto cleanup;
380	if (qpol_type_get_isattr(q, type_datum, &isattr))
381		goto cleanup;
382	if (qpol_type_get_isalias(q, type_datum, &isalias))
383		goto cleanup;
384
385	if (qpol_type_get_alias_iter(q, type_datum, &iter))
386		goto cleanup;
387	if (qpol_iterator_get_size(iter, &alias_size))
388		goto cleanup;
389	if (alias_size >  0) {
390		for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
391			if (qpol_iterator_get_item(iter, (void **)&alias_name))
392				goto err;
393			if (py_append_string(list, alias_name))
394				goto err;
395		}
396	}
397	goto cleanup;
398
399err:
400	error = errno;
401	PyErr_SetString(PyExc_RuntimeError,strerror(errno));
402	py_decref(list); list = NULL;
403
404cleanup:
405	qpol_iterator_destroy(&iter);
406	errno = error;
407	return list;
408}
409
410/**
411 * Gets a textual representation of an attribute, and
412 * all of that attribute's types.
413 *
414 * @param type_datum Reference to sepol type_datum
415 * @param policydb Reference to a policy
416 */
417static PyObject* get_attr(const qpol_type_t * type_datum, const apol_policy_t * policydb)
418{
419	PyObject *list = NULL;
420	const qpol_type_t *attr_datum = NULL;
421	qpol_iterator_t *iter = NULL;
422	const char *attr_name = NULL, *type_name = NULL;
423	qpol_policy_t *q = apol_policy_get_qpol(policydb);
424	unsigned char isattr;
425	int error = 0;
426	int rt = 0;
427	PyObject *dict = PyDict_New();
428	if (!dict) goto err;
429
430	if (qpol_type_get_name(q, type_datum, &attr_name))
431		goto err;
432
433	if (py_insert_string(dict, "name", attr_name))
434		goto err;
435
436	/* get an iterator over all types this attribute has */
437	if (qpol_type_get_isattr(q, type_datum, &isattr))
438		goto err;
439
440	if (isattr) {	       /* sanity check */
441		if (qpol_type_get_type_iter(q, type_datum, &iter))
442			goto err;
443		list = PyList_New(0);
444		if (!list) goto err;
445
446		for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
447			if (qpol_iterator_get_item(iter, (void **)&attr_datum))
448				goto err;
449			if (qpol_type_get_name(q, attr_datum, &type_name))
450				goto err;
451			if (py_append_string(list, type_name))
452				goto err;
453		}
454		qpol_iterator_destroy(&iter);
455		rt = PyDict_SetItemString(dict, "types", list);
456		Py_DECREF(list); list = NULL;
457		if (rt) goto err;
458	} else		       /* this should never happen */
459		goto err;
460	goto cleanup;
461
462err:
463	error = errno;
464	PyErr_SetString(PyExc_RuntimeError,strerror(errno));
465	py_decref(dict); dict = NULL;
466	py_decref(list);
467
468cleanup:
469	qpol_iterator_destroy(&iter);
470	errno =	error;
471	return dict;
472}
473
474/**
475 * Gets statistics regarding a policy's attributes.
476 * If this function is given a name, it will attempt to
477 * get statistics about a particular attribute; otherwise
478 * the function gets statistics about all of the policy's
479 * attributes.
480 *
481 * @param name Reference to an attribute's name; if NULL,
482 * all object classes will be considered
483 * @param policydb Reference to a policy
484 *
485 * @return 0 on success, < 0 on error.
486 */
487static PyObject* get_attribs(const char *name, const apol_policy_t * policydb)
488{
489	PyObject *obj;
490	apol_attr_query_t *attr_query = NULL;
491	apol_vector_t *v = NULL;
492	const qpol_type_t *type_datum = NULL;
493	size_t n_attrs, i;
494	int error = 0;
495	int rt = 0;
496	PyObject *list = PyList_New(0);
497	if (!list) goto err;
498
499	/* we are only getting information about 1 attribute */
500	if (name != NULL) {
501		attr_query = apol_attr_query_create();
502		if (!attr_query)
503			goto err;
504		if (apol_attr_query_set_attr(policydb, attr_query, name))
505			goto err;
506		if (apol_attr_get_by_query(policydb, attr_query, &v))
507			goto err;
508		apol_attr_query_destroy(&attr_query);
509		if (apol_vector_get_size(v) == 0) {
510			apol_vector_destroy(&v);
511			errno = EINVAL;
512			goto err;
513		}
514
515		type_datum = apol_vector_get_element(v, (size_t) 0);
516		obj = get_attr(type_datum, policydb);
517		rt = py_append_obj(list, obj);
518		Py_DECREF(obj);
519		if (rt) goto err;
520	} else {
521		attr_query = apol_attr_query_create();
522		if (!attr_query)
523			goto err;
524		if (apol_attr_get_by_query(policydb, attr_query, &v))
525			goto err;
526		apol_attr_query_destroy(&attr_query);
527		n_attrs = apol_vector_get_size(v);
528
529		for (i = 0; i < n_attrs; i++) {
530			/* get qpol_type_t* item from vector */
531			type_datum = (qpol_type_t *) apol_vector_get_element(v, (size_t) i);
532			if (!type_datum)
533				goto err;
534			obj = get_attr(type_datum, policydb);
535			rt = py_append_obj(list, obj);
536			Py_DECREF(obj);
537			if (rt) goto err;
538		}
539	}
540	apol_vector_destroy(&v);
541	goto cleanup;
542
543err:
544	error = errno;
545	PyErr_SetString(PyExc_RuntimeError,strerror(errno));
546	py_decref(list); list = NULL;
547
548cleanup:
549	apol_attr_query_destroy(&attr_query);
550	apol_vector_destroy(&v);
551	errno = error;
552	return list;
553}
554
555/**
556 * Get a textual representation of a type, and
557 * all of that type's attributes.
558 *
559 * @param type_datum Reference to sepol type_datum
560 * @param policydb Reference to a policy
561 */
562static PyObject* get_type_attrs(const qpol_type_t * type_datum, const apol_policy_t * policydb)
563{
564	qpol_iterator_t *iter = NULL;
565	const char *attr_name = NULL;
566	const qpol_type_t *attr_datum = NULL;
567	qpol_policy_t *q = apol_policy_get_qpol(policydb);
568	int error = 0;
569	PyObject *list = PyList_New(0);
570	if (!list) goto err;
571
572	if (qpol_type_get_attr_iter(q, type_datum, &iter))
573		goto err;
574
575	for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
576		if (qpol_iterator_get_item(iter, (void **)&attr_datum))
577			goto err;
578		if (qpol_type_get_name(q, attr_datum, &attr_name))
579			goto err;
580		if (py_append_string(list, attr_name))
581			goto err;
582	}
583	goto cleanup;
584
585err:
586	error = errno;
587	PyErr_SetString(PyExc_RuntimeError,strerror(errno));
588	py_decref(list); list = NULL;
589
590cleanup:
591	qpol_iterator_destroy(&iter);
592	errno = error;
593	return list;
594}
595
596static PyObject* get_type(const qpol_type_t * type_datum, const apol_policy_t * policydb) {
597
598	PyObject *obj;
599	qpol_policy_t *q = apol_policy_get_qpol(policydb);
600	const char *type_name = NULL;
601	int error = 0;
602	int rt;
603	unsigned char isalias, ispermissive, isattr;
604	PyObject *dict = PyDict_New();
605	if (!dict) goto err;
606
607	if (qpol_type_get_name(q, type_datum, &type_name))
608		goto err;
609	if (qpol_type_get_isalias(q, type_datum, &isalias))
610		goto err;
611	if (qpol_type_get_isattr(q, type_datum, &isattr))
612		goto err;
613	if (qpol_type_get_ispermissive(q, type_datum, &ispermissive))
614		goto err;
615
616	if (py_insert_string(dict, "name", type_name))
617		goto err;
618
619	if (py_insert_bool(dict, "permissive", ispermissive))
620		goto err;
621
622	if (!isattr && !isalias) {
623		obj = get_type_attrs(type_datum, policydb);
624		rt = py_insert_obj(dict, "attributes", obj);
625		Py_DECREF(obj);
626		if (rt) goto err;
627	}
628
629	obj = get_type_aliases(type_datum, policydb);
630	rt = py_insert_obj(dict, "aliases", obj);
631	Py_DECREF(obj);
632	if (rt) goto err;
633	goto cleanup;
634
635err:
636	error = errno;
637	PyErr_SetString(PyExc_RuntimeError,strerror(error));
638	py_decref(dict); dict = NULL;
639
640cleanup:
641	errno = error;
642	return dict;
643}
644
645/**
646 * Gets statistics regarding a policy's booleans.
647 * If this function is given a name, it will attempt to
648 * get statistics about a particular boolean; otherwise
649 * the function gets statistics about all of the policy's booleans.
650 *
651 * @param name Reference to a boolean's name; if NULL,
652 * all booleans will be considered
653 * @param policydb Reference to a policy
654 *
655 * @return new reference, or NULL (setting an exception)
656 */
657static PyObject* get_booleans(const char *name, const apol_policy_t * policydb)
658{
659	PyObject *dict = NULL;
660	int error = 0;
661	int rt = 0;
662	const char *bool_name = NULL;
663	int state;
664	qpol_bool_t *bool_datum = NULL;
665	qpol_iterator_t *iter = NULL;
666	qpol_policy_t *q = apol_policy_get_qpol(policydb);
667	size_t n_bools = 0;
668	PyObject *list = PyList_New(0);
669	if (!list) goto err;
670
671	if (name != NULL) {
672		if (qpol_policy_get_bool_by_name(q, name, &bool_datum))
673			goto err;
674		if (qpol_bool_get_state(q, bool_datum, &state))
675			goto err;
676
677		dict = PyDict_New();
678		if (!dict) goto err;
679		if (py_insert_string(dict, "name", name))
680			goto err;
681		if (py_insert_bool(dict, "name", state))
682			goto err;
683		rt = py_append_obj(list, dict);
684		Py_DECREF(dict); dict = NULL;
685		if (rt) goto err;
686	} else {
687		if (qpol_policy_get_bool_iter(q, &iter))
688			goto err;
689		if (qpol_iterator_get_size(iter, &n_bools))
690			goto err;
691		for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
692			if (qpol_iterator_get_item(iter, (void **)&bool_datum))
693				goto err;
694			if (qpol_bool_get_name(q, bool_datum, &bool_name))
695				goto err;
696			if (qpol_bool_get_state(q, bool_datum, &state))
697				goto err;
698
699			dict = PyDict_New();
700			if (!dict) goto err;
701			if (py_insert_string(dict, "name", bool_name))
702				goto err;
703			if (py_insert_bool(dict, "state", state))
704				goto err;
705			rt = py_append_obj(list, dict);
706			Py_DECREF(dict); dict = NULL;
707			if (rt) goto err;
708		}
709		qpol_iterator_destroy(&iter);
710	}
711	goto cleanup;
712
713err:
714	error = errno;
715	PyErr_SetString(PyExc_RuntimeError,strerror(error));
716	py_decref(list); list = NULL;
717	py_decref(dict); dict = NULL;
718
719cleanup:
720	qpol_iterator_destroy(&iter);
721	errno = error;
722	return list;
723}
724
725/**
726 * Gets a textual representation of a user, and
727 * all of that user's roles.
728 *
729 * @param type_datum Reference to sepol type_datum
730 * @param policydb Reference to a policy
731 * roles
732 */
733static PyObject* get_user(const qpol_user_t * user_datum, const apol_policy_t * policydb)
734{
735	int error = 0;
736	int rt;
737	const qpol_role_t *role_datum = NULL;
738	qpol_iterator_t *iter = NULL;
739	const qpol_mls_range_t *range = NULL;
740	const qpol_mls_level_t *dflt_level = NULL;
741	apol_mls_level_t *ap_lvl = NULL;
742	apol_mls_range_t *ap_range = NULL;
743	qpol_policy_t *q = apol_policy_get_qpol(policydb);
744	char *tmp = NULL;
745	const char *user_name, *role_name;
746	PyObject *dict = NULL;
747	PyObject *list = PyList_New(0);
748	if (!list) goto err;
749
750	if (qpol_user_get_name(q, user_datum, &user_name))
751		goto err;
752
753	dict = PyDict_New();
754	if (!dict) goto err;
755
756	if (py_insert_string(dict, "name", user_name))
757		goto err;
758
759	if (qpol_policy_has_capability(q, QPOL_CAP_MLS)) {
760		if (qpol_user_get_dfltlevel(q, user_datum, &dflt_level))
761			goto err;
762		ap_lvl = apol_mls_level_create_from_qpol_mls_level(policydb, dflt_level);
763		tmp = apol_mls_level_render(policydb, ap_lvl);
764		if (!tmp) goto err;
765		if (py_insert_string(dict, "level", tmp))
766		    goto err;
767		free(tmp); tmp = NULL;
768
769		if (qpol_user_get_range(q, user_datum, &range))
770			goto err;
771		ap_range = apol_mls_range_create_from_qpol_mls_range(policydb, range);
772		tmp = apol_mls_range_render(policydb, ap_range);
773		if (!tmp) goto err;
774		if (py_insert_string(dict, "range", tmp))
775		    goto err;
776		free(tmp); tmp=NULL;
777	}
778
779	if (qpol_user_get_role_iter(q, user_datum, &iter))
780		goto err;
781	for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
782		if (qpol_iterator_get_item(iter, (void **)&role_datum))
783			goto err;
784		if (qpol_role_get_name(q, role_datum, &role_name))
785			goto err;
786		if (py_append_string(list, role_name))
787			goto err;
788	}
789
790	rt = py_insert_obj(dict, "roles", list);
791	Py_DECREF(list); list=NULL;
792	if (rt) goto err;
793	goto cleanup;
794
795err:
796	error = errno;
797	PyErr_SetString(PyExc_RuntimeError,strerror(errno));
798	py_decref(list); list=NULL;
799	py_decref(dict); dict=NULL;
800
801cleanup:
802	free(tmp);
803	qpol_iterator_destroy(&iter);
804	apol_mls_level_destroy(&ap_lvl);
805	apol_mls_range_destroy(&ap_range);
806	errno = error;
807	return dict;
808}
809
810/**
811 * Prints a textual representation of an object class and possibly
812 * all of that object class' permissions.
813 *
814 * @param type_datum Reference to sepol type_datum
815 * @param policydb Reference to a policy
816 */
817static PyObject* get_class(const qpol_class_t * class_datum, const apol_policy_t * policydb)
818{
819	const char *class_name = NULL, *perm_name = NULL;
820	qpol_iterator_t *iter = NULL;
821	const qpol_common_t *common_datum = NULL;
822	qpol_policy_t *q = apol_policy_get_qpol(policydb);
823	int error = 0;
824	int rt;
825	PyObject *list = NULL;
826	PyObject *dict = PyDict_New();
827	if (!dict) goto err;
828
829	if (!class_datum)
830		goto err;
831
832	if (qpol_class_get_name(q, class_datum, &class_name))
833		goto err;
834
835	if (py_insert_string(dict, "name", class_name))
836		goto err;
837	/* get commons for this class */
838	if (qpol_class_get_common(q, class_datum, &common_datum))
839		goto err;
840
841	list = PyList_New(0);
842	if (!list) goto err;
843
844	if (common_datum) {
845		if (qpol_common_get_perm_iter(q, common_datum, &iter))
846			goto err;
847		/* print perms for the common */
848		for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
849			if (qpol_iterator_get_item(iter, (void **)&perm_name))
850				goto err;
851			if (py_append_string(list, perm_name))
852				goto err;
853		}
854	}
855	/* print unique perms for this class */
856	if (qpol_class_get_perm_iter(q, class_datum, &iter))
857		goto err;
858	for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
859		if (qpol_iterator_get_item(iter, (void **)&perm_name))
860			goto err;
861		if (py_append_string(list, perm_name))
862			goto err;
863	}
864	rt = py_insert_obj(dict, "permlist", list);
865	Py_DECREF(list); list = NULL;
866	if (rt) goto err;
867	qpol_iterator_destroy(&iter);
868	goto cleanup;
869
870err:
871	error = errno;
872	PyErr_SetString(PyExc_RuntimeError,strerror(errno));
873	py_decref(list); list=NULL;
874	py_decref(dict); dict=NULL;
875
876cleanup:
877	errno = error;
878	qpol_iterator_destroy(&iter);
879	return dict;
880}
881
882/**
883 * Get statistics regarding a policy's object classes.
884 * If this function is given a name, it will attempt to
885 * print statistics about a particular object class; otherwise
886 * the function prints statistics about all of the policy's object
887 * classes.
888 *
889 * @param name Reference to an object class' name; if NULL,
890 * all object classes will be considered
891 * @param policydb Reference to a policy
892 *
893 * @return 0 on success, < 0 on error.
894 */
895static PyObject*  get_classes(const char *name, const apol_policy_t * policydb)
896{
897	qpol_iterator_t *iter = NULL;
898	size_t n_classes = 0;
899	const qpol_class_t *class_datum = NULL;
900	qpol_policy_t *q = apol_policy_get_qpol(policydb);
901	int error = 0;
902	int rt;
903	PyObject *obj;
904	PyObject *list = PyList_New(0);
905	if (!list) goto err;
906
907	if (name != NULL) {
908		if (qpol_policy_get_class_by_name(q, name, &class_datum))
909			goto err;
910		obj = get_class(class_datum, policydb);
911		rt = py_append_obj(list, obj);
912		Py_DECREF(obj);
913		if (rt) goto err;
914	} else {
915		if (qpol_policy_get_class_iter(q, &iter))
916			goto err;
917		if (qpol_iterator_get_size(iter, &n_classes))
918			goto err;
919
920		for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
921			if (qpol_iterator_get_item(iter, (void **)&class_datum))
922				goto err;
923			obj = get_class(class_datum, policydb);
924			rt = py_append_obj(list, obj);
925			Py_DECREF(obj);
926			if (rt) goto err;
927		}
928		qpol_iterator_destroy(&iter);
929	}
930	goto cleanup;
931err:
932	error = errno;
933	PyErr_SetString(PyExc_RuntimeError,strerror(errno));
934	py_decref(list); list = NULL;
935
936cleanup:
937	qpol_iterator_destroy(&iter);
938	errno = error;
939	return list;
940}
941
942/**
943 * Gets statistics regarding a policy's users.
944 * If this function is given a name, it will attempt to
945 * get statistics about a particular user; otherwise
946 * the function gets statistics about all of the policy's
947 * users.
948 *
949 * @param name Reference to a user's name; if NULL,
950 * all users will be considered
951 * @param policydb Reference to a policy
952 *
953 * @return 0 on success, < 0 on error.
954 */
955static PyObject*  get_users(const char *name, const apol_policy_t * policydb)
956{
957	qpol_iterator_t *iter = NULL;
958	const qpol_user_t *user_datum = NULL;
959	qpol_policy_t *q = apol_policy_get_qpol(policydb);
960	int error = 0;
961	int rt;
962	PyObject *obj;
963	PyObject *list = PyList_New(0);
964	if (!list) goto err;
965
966	if (name != NULL) {
967		if (qpol_policy_get_user_by_name(q, name, &user_datum)) {
968			errno = EINVAL;
969			goto err;
970		}
971		obj = get_user(user_datum, policydb);
972		rt = py_append_obj(list, obj);
973		Py_DECREF(obj);
974		if (rt) goto err;
975	} else {
976		if (qpol_policy_get_user_iter(q, &iter))
977			goto err;
978
979		for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
980			if (qpol_iterator_get_item(iter, (void **)&user_datum))
981				goto err;
982			obj = get_user(user_datum, policydb);
983			rt = py_append_obj(list, obj);
984			Py_DECREF(obj);
985			if (rt) goto err;
986		}
987		qpol_iterator_destroy(&iter);
988	}
989	goto cleanup;
990
991err:
992	error = errno;
993	PyErr_SetString(PyExc_RuntimeError,strerror(errno));
994	py_decref(list); list = NULL;
995
996cleanup:
997	qpol_iterator_destroy(&iter);
998	errno = error;
999	return list;
1000}
1001
1002/**
1003 * get a textual representation of a role, and
1004 * all of that role's types.
1005 *
1006 * @param type_datum Reference to sepol type_datum
1007 * @param policydb Reference to a policy
1008 * types
1009 */
1010static PyObject* get_role(const qpol_role_t * role_datum, const apol_policy_t * policydb)
1011{
1012	const char *role_name = NULL, *type_name = NULL;
1013	const qpol_role_t *dom_datum = NULL;
1014	const qpol_type_t *type_datum = NULL;
1015	qpol_iterator_t *iter = NULL;
1016	qpol_policy_t *q = apol_policy_get_qpol(policydb);
1017	size_t n_dom = 0, n_types = 0;
1018	int error = 0;
1019	int rt;
1020	PyObject *list = NULL;
1021	PyObject *dict = PyDict_New();
1022	if (!dict) goto err;
1023
1024	if (qpol_role_get_name(q, role_datum, &role_name))
1025		goto err;
1026	if (py_insert_string(dict, "name", role_name))
1027		goto err;
1028
1029	if (qpol_role_get_dominate_iter(q, role_datum, &iter))
1030		goto err;
1031	if (qpol_iterator_get_size(iter, &n_dom))
1032		goto err;
1033	if ((int)n_dom > 0) {
1034		list = PyList_New(0);
1035		if (!list) goto err;
1036		for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
1037			if (qpol_iterator_get_item(iter, (void **)&dom_datum))
1038				goto err;
1039			if (qpol_role_get_name(q, dom_datum, &role_name))
1040				goto err;
1041			if (py_append_string(list, role_name))
1042				goto err;
1043		}
1044		rt = py_insert_obj(dict, "roles", list);
1045		Py_DECREF(list); list = NULL;
1046		if (rt) goto err;
1047	}
1048	qpol_iterator_destroy(&iter);
1049
1050	if (qpol_role_get_type_iter(q, role_datum, &iter))
1051		goto err;
1052	if (qpol_iterator_get_size(iter, &n_types))
1053		goto err;
1054	if ((int)n_types > 0) {
1055		list = PyList_New(0);
1056		if (!list) goto err;
1057		for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
1058			if (qpol_iterator_get_item(iter, (void **)&type_datum))
1059				goto err;
1060			if (qpol_type_get_name(q, type_datum, &type_name))
1061				goto err;
1062			if (py_append_string(list, type_name))
1063				goto err;
1064		}
1065		rt = py_insert_obj(dict, "types", list);
1066		Py_DECREF(list); list = NULL;
1067		if (rt) goto err;
1068	}
1069	goto cleanup;
1070
1071err:
1072	error = errno;
1073	PyErr_SetString(PyExc_RuntimeError,strerror(errno));
1074	py_decref(list); list = NULL;
1075	py_decref(dict); dict = NULL;
1076
1077cleanup:
1078	qpol_iterator_destroy(&iter);
1079	errno =	error;
1080	return dict;
1081}
1082
1083/**
1084 * Get statistics regarding a policy's ports.
1085 * If this function is given a name, it will attempt to
1086 * get statistics about a particular port; otherwise
1087 * the function get statistics about all of the policy's ports.
1088 *
1089 * @param name Reference to an port's name; if NULL,
1090 * all ports will be considered
1091 * @param policydb Reference to a policy
1092 *
1093 * @return 0 on success, < 0 on error.
1094 */
1095static PyObject*  get_ports(const char *num, const apol_policy_t * policydb)
1096{
1097	const qpol_portcon_t *portcon = NULL;
1098	qpol_iterator_t *iter = NULL;
1099	uint16_t low_port, high_port;
1100	uint8_t ocon_proto;
1101	qpol_policy_t *q = apol_policy_get_qpol(policydb);
1102	const qpol_context_t *ctxt = NULL;
1103	const char *proto_str = NULL;
1104	const char *type = NULL;
1105	const apol_mls_range_t *range = NULL;
1106	char *range_str = NULL;
1107	apol_context_t *c = NULL;
1108	int error = 0;
1109	int rt = 0;
1110	PyObject *dict = NULL;
1111	PyObject *list = PyList_New(0);
1112	if (!list) goto err;
1113
1114	if (qpol_policy_get_portcon_iter(q, &iter))
1115		goto err;
1116
1117	for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
1118		if (qpol_iterator_get_item(iter, (void **)&portcon))
1119			goto err;
1120		if (qpol_portcon_get_low_port(q, portcon, &low_port))
1121			goto err;
1122		if (qpol_portcon_get_high_port(q, portcon, &high_port))
1123			goto err;
1124		if (qpol_portcon_get_protocol(q, portcon, &ocon_proto))
1125			goto err;
1126		if (num) {
1127			if (atoi(num) < low_port || atoi(num) > high_port)
1128				continue;
1129		}
1130
1131		if ((ocon_proto != IPPROTO_TCP) &&
1132		    (ocon_proto != IPPROTO_UDP))
1133			goto err;
1134
1135		if (qpol_portcon_get_context(q, portcon, &ctxt)) {
1136			PyErr_SetString(PyExc_RuntimeError, "Could not get for port context.");
1137			goto err;
1138		}
1139
1140		if ((proto_str = apol_protocol_to_str(ocon_proto)) == NULL) {
1141			PyErr_SetString(PyExc_RuntimeError, "Invalid protocol for port");
1142			goto err;
1143		}
1144
1145		if ((c = apol_context_create_from_qpol_context(policydb, ctxt)) == NULL) {
1146			goto err;
1147		}
1148
1149		if((type = apol_context_get_type(c)) == NULL) {
1150			apol_context_destroy(&c);
1151			goto err;
1152		}
1153
1154		dict = PyDict_New();
1155		if (!dict) goto err;
1156		if (py_insert_string(dict, "type", type))
1157			goto err;
1158
1159		if((range = apol_context_get_range(c)) != NULL) {
1160			range_str = apol_mls_range_render(policydb, range);
1161			if (range_str == NULL) {
1162				goto err;
1163			}
1164			if (py_insert_string(dict, "range", range_str))
1165				goto err;
1166		}
1167
1168		if (py_insert_string(dict, "protocol", proto_str))
1169			goto err;
1170
1171		if (py_insert_long(dict, "high", high_port))
1172			goto err;
1173
1174		if (py_insert_long(dict, "low", low_port))
1175			goto err;
1176
1177		rt = py_append_obj(list, dict);
1178		Py_DECREF(dict); dict = NULL;
1179		if (rt) goto err;
1180	}
1181	goto cleanup;
1182
1183err:
1184	error = errno;
1185	PyErr_SetString(PyExc_RuntimeError,strerror(errno));
1186	py_decref(list); list = NULL;
1187	py_decref(dict); dict = NULL;
1188
1189cleanup:
1190	free(range_str);
1191	apol_context_destroy(&c);
1192	qpol_iterator_destroy(&iter);
1193	errno = error;
1194	return list;
1195}
1196
1197/**
1198 * Get statistics regarding a policy's roles.
1199 * If this function is given a name, it will attempt to
1200 * get statistics about a particular role; otherwise
1201 * the function get statistics about all of the policy's roles.
1202 *
1203 * @param name Reference to an role's name; if NULL,
1204 * all roles will be considered
1205 * @param policydb Reference to a policy
1206 *
1207 * @return 0 on success, < 0 on error.
1208 */
1209static PyObject*  get_roles(const char *name, const apol_policy_t * policydb)
1210{
1211	const qpol_role_t *role_datum = NULL;
1212	qpol_iterator_t *iter = NULL;
1213	qpol_policy_t *q = apol_policy_get_qpol(policydb);
1214	int error = 0;
1215	int rt;
1216	PyObject *obj;
1217	PyObject *list = PyList_New(0);
1218	if (!list) goto err;
1219
1220	if (name != NULL) {
1221		if (qpol_policy_get_role_by_name(q, name, &role_datum)) {
1222			errno = EINVAL;
1223			goto err;
1224		}
1225		obj = get_role(role_datum, policydb);
1226		rt = py_append_obj(list, obj);
1227		Py_DECREF(obj);
1228		if (rt) goto err;
1229	} else {
1230		if (qpol_policy_get_role_iter(q, &iter))
1231			goto err;
1232
1233		for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
1234			if (qpol_iterator_get_item(iter, (void **)&role_datum))
1235				goto err;
1236			obj = get_role(role_datum, policydb);
1237			rt = py_append_obj(list, obj);
1238			Py_DECREF(obj);
1239			if (rt) goto err;
1240		}
1241		qpol_iterator_destroy(&iter);
1242	}
1243	goto cleanup;
1244
1245err:
1246	error = errno;
1247	PyErr_SetString(PyExc_RuntimeError,strerror(errno));
1248	py_decref(list); list = NULL;
1249
1250cleanup:
1251	qpol_iterator_destroy(&iter);
1252	errno = error;
1253	return list;
1254}
1255
1256/**
1257 * Get statistics regarding a policy's types.
1258 * If this function is given a name, it will attempt to
1259 * print statistics about a particular type; otherwise
1260 * the function prints statistics about all of the policy's types.
1261 *
1262 * @param name Reference to a type's name; if NULL,
1263 * all object classes will be considered
1264 * @param policydb Reference to a policy
1265 *
1266 * @return 0 on success, < 0 on error.
1267 */
1268static PyObject* get_types(const char *name, const apol_policy_t * policydb)
1269{
1270	const qpol_type_t *type_datum = NULL;
1271	qpol_iterator_t *iter = NULL;
1272	qpol_policy_t *q = apol_policy_get_qpol(policydb);
1273	int error = 0;
1274	int rt;
1275	PyObject *obj;
1276	PyObject *list = PyList_New(0);
1277	if (!list) goto err;
1278	/* if name was provided, only print that name */
1279	if (name != NULL) {
1280		if (qpol_policy_get_type_by_name(q, name, &type_datum)) {
1281			errno = EINVAL;
1282			goto err;
1283		}
1284		obj = get_type(type_datum, policydb);
1285		rt = py_append_obj(list, obj);
1286		Py_DECREF(obj);
1287		if (rt) goto err;
1288	} else {
1289		if (qpol_policy_get_type_iter(q, &iter))
1290			goto err;
1291
1292		for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
1293			if (qpol_iterator_get_item(iter, (void **)&type_datum))
1294				goto err;
1295			obj = get_type(type_datum, policydb);
1296			rt = py_append_obj(list, obj);
1297			Py_DECREF(obj);
1298			if (rt) goto err;
1299		}
1300	}
1301	goto cleanup;
1302
1303err:
1304	error = errno;
1305	PyErr_SetString(PyExc_RuntimeError,strerror(errno));
1306	py_decref(list); list = NULL;
1307
1308cleanup:
1309	qpol_iterator_destroy(&iter);
1310	errno =	error;
1311	return list;
1312}
1313
1314PyObject* info( int type, const char *name)
1315{
1316	PyObject* output = NULL;
1317
1318	switch(type) {
1319	/* display requested info */
1320	case TYPE:
1321		output = get_types(name, policy);
1322		break;
1323	case ATTRIBUTE:
1324		output = get_attribs(name, policy);
1325		break;
1326	case ROLE:
1327		output = get_roles(name, policy);
1328		break;
1329	case USER:
1330		output = get_users(name, policy);
1331		break;
1332	case CLASS:
1333		output = get_classes(name, policy);
1334		break;
1335	case BOOLEAN:
1336		output = get_booleans(name, policy);
1337		break;
1338	case PORT:
1339		output = get_ports(name, policy);
1340		break;
1341	case SENS:
1342		output = get_sens(name, policy);
1343		break;
1344	case CATS:
1345		output = get_cats(name, policy);
1346		break;
1347	default:
1348		errno = EINVAL;
1349		PyErr_SetString(PyExc_RuntimeError,strerror(errno));
1350		break;
1351	}
1352
1353	return output;
1354}
1355
1356PyObject *wrap_info(PyObject *UNUSED(self), PyObject *args){
1357    int type;
1358    const char *name;
1359
1360    if (!policy) {
1361	    PyErr_SetString(PyExc_RuntimeError,"Policy not loaded");
1362	    return NULL;
1363    }
1364
1365    if (!PyArg_ParseTuple(args, "iz", &type, &name))
1366        return NULL;
1367
1368    return info(type, name);
1369}
1370
1371void init_info (PyObject *m) {
1372    PyModule_AddIntConstant(m, "ATTRIBUTE", ATTRIBUTE);
1373    PyModule_AddIntConstant(m, "PORT", PORT);
1374    PyModule_AddIntConstant(m, "ROLE", ROLE);
1375    PyModule_AddIntConstant(m, "TYPE", TYPE);
1376    PyModule_AddIntConstant(m, "USER", USER);
1377    PyModule_AddIntConstant(m, "CLASS", CLASS);
1378    PyModule_AddIntConstant(m, "BOOLEAN", BOOLEAN);
1379    PyModule_AddIntConstant(m, "SENS", SENS);
1380    PyModule_AddIntConstant(m, "CATS", CATS);
1381}
1382