From 47be9ff57e72906660bb62a515222f482131e1fb Mon Sep 17 00:00:00 2001 From: Miroslav Grepl Date: Fri, 11 Apr 2014 09:37:53 +0200 Subject: Create setools-3.3.7 git repo --- apol/apol_tcl.i | 451 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 451 insertions(+) create mode 100644 apol/apol_tcl.i (limited to 'apol/apol_tcl.i') diff --git a/apol/apol_tcl.i b/apol/apol_tcl.i new file mode 100644 index 0000000..973c859 --- /dev/null +++ b/apol/apol_tcl.i @@ -0,0 +1,451 @@ +/** + * @file + * + * Support routines for the apol program that are faster/easier when + * written in C than in Tcl. + * + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * + * Copyright (C) 2006-2007 Tresys Technology, LLC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +%module apol_tcl +%import sefs.i +%import apol.i +%import qpol.i + +%{ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +%} + +%{ +/* Note that these must be placed in a different file rather than + * being inlined directly into this SWIG interface file. The reason + * is because they use some GNU functions that are only available when + * config.h is included prior to stdio.h. Unfortunately, SWIG will + * always place its own headers, which includes stdio.h, prior to any + * inlined headers when generating the wrapped C file. As a result, + * those GNU functions would not be available to the inlined + * functions. + */ +extern void apol_tcl_clear_info_string(void); +extern int apol_tcl_get_info_level(void); +extern char *apol_tcl_get_info_string(void); +extern void apol_tcl_set_info_string(apol_policy_t *p, const char *s); +extern void apol_tcl_route_apol_to_string(void *arg, const apol_policy_t * p, int level, const char *fmt, va_list ap); +extern void apol_tcl_route_sefs_to_string(void *arg, const sefs_fclist * s, int level, const char *fmt, va_list ap); +extern int msg_level; +extern char *message; + +static void tcl_clear_error(void) +{ + apol_tcl_clear_info_string(); +} +static void tcl_throw_error(const char *s) +{ + free(message); + message = strdup(s); +} +static char *tcl_get_error(void) +{ + if (msg_level != APOL_MSG_ERR) { + return NULL; + } + return apol_tcl_get_info_string(); +} +#undef SWIG_exception +#define SWIG_exception(code, msg) {tcl_throw_error(msg); goto fail;} +%} + +/* Major hackery here to pass in the Tcl interpreter object as + * apol_policy_create_from_policy_path()'s callback argument. This is + * needed so that the callback can properly update apol's progress + * dialog without deadlocking itself. + */ +%newobject apol_tcl_open_policy(const apol_policy_path_t *, Tcl_Interp *); +%typemap (in) (const apol_policy_path_t *ppath, Tcl_Interp *interp) { + int res = SWIG_ConvertPtr($input, SWIG_as_voidptrptr(&$1), $1_descriptor, 0); + if (res) { + SWIG_exception_fail(SWIG_ArgError(res), "in method '" "apol_tcl_open_policy" "', argument " "1"" of type '" "apol_policy_path_t const *""'"); + } + $2 = interp; +}; +%inline %{ + /** + * Open a policy file, either source or binary, on disk. Note + * that this will not load neverallows; apol must rebuild + * neverallows (and call qpol_policy_build_syn_rule_table()) + * when it needs to. If the file was opened successfully then + * allocate and return an apol_policy_t object. Otherwise + * throw an error and return a string that describes the + * error. + * + * @param ppath apol_policy_path object representing policy to + * open. + */ + apol_policy_t *apol_tcl_open_policy(const apol_policy_path_t *ppath, Tcl_Interp *interp) { + apol_policy_t *p = apol_policy_create_from_policy_path(ppath, QPOL_POLICY_OPTION_NO_NEVERALLOWS, + apol_tcl_route_apol_to_string, interp); + if (p == NULL && message == NULL) { // Assume lower level has generated error message + if (errno != 0) { // otherwise take a guess at it + SWIG_exception(SWIG_RuntimeError, strerror(errno)); + } else { + SWIG_exception(SWIG_RuntimeError, "The selected file does not appear to be a valid SELinux Policy."); + } + } + fail: + return p; + } + + static int avrule_sort(const void *a, const void *b, void *arg) { + const qpol_avrule_t *r1 = static_cast(a); + const qpol_avrule_t *r2 = static_cast(b); + apol_policy_t *p = static_cast(arg); + qpol_policy_t *q = apol_policy_get_qpol(p); + + uint32_t rule_type1, rule_type2; + const char *cs1, *cs2; + int compval; + if (qpol_avrule_get_rule_type(q, r1, &rule_type1) < 0 || + qpol_avrule_get_rule_type(q, r2, &rule_type2) < 0) { + return 0; + } + if ((cs1 = apol_rule_type_to_str(rule_type1)) == NULL || + (cs2 = apol_rule_type_to_str(rule_type2)) == NULL) { + return 0; + } + if ((compval = strcmp(cs1, cs2)) != 0) { + return compval; + } + + const qpol_type_t *t1, *t2; + const char *s1, *s2; + if (qpol_avrule_get_source_type(q, r1, &t1) < 0 || + qpol_avrule_get_source_type(q, r2, &t2) < 0) { + return 0; + } + if (qpol_type_get_name(q, t1, &s1) < 0 || + qpol_type_get_name(q, t2, &s2) < 0) { + return 0; + } + if ((compval = strcmp(s1, s2)) != 0) { + return compval; + } + + if (qpol_avrule_get_target_type(q, r1, &t1) < 0 || + qpol_avrule_get_target_type(q, r2, &t2) < 0) { + return 0; + } + if (qpol_type_get_name(q, t1, &s1) < 0 || + qpol_type_get_name(q, t2, &s2) < 0) { + return 0; + } + if ((compval = strcmp(s1, s2)) != 0) { + return compval; + } + + const qpol_class_t *c1, *c2; + if (qpol_avrule_get_object_class(q, r1, &c1) < 0 || + qpol_avrule_get_object_class(q, r2, &c2) < 0) { + return 0; + } + if (qpol_class_get_name(q, c1, &s1) < 0 || + qpol_class_get_name(q, c2, &s2) < 0) { + return 0; + } + return strcmp(s1, s2); + } + + /** + * Sort a vector of qpol_avrule_t, sorting by rule type, then + * source type, then target type, and then by object class. + */ + void apol_tcl_avrule_sort(apol_policy_t *policy, apol_vector_t *v) { + if (policy != NULL && v != NULL) { + apol_vector_sort(v, avrule_sort, policy); + } + } + + static int terule_sort(const void *a, const void *b, void *arg) { + const qpol_terule_t *r1 = static_cast(a); + const qpol_terule_t *r2 = static_cast(b); + apol_policy_t *p = static_cast(arg); + qpol_policy_t *q = apol_policy_get_qpol(p); + + uint32_t rule_type1, rule_type2; + const char *cs1, *cs2; + int compval; + if (qpol_terule_get_rule_type(q, r1, &rule_type1) < 0 || + qpol_terule_get_rule_type(q, r2, &rule_type2) < 0) { + return 0; + } + if ((cs1 = apol_rule_type_to_str(rule_type1)) == NULL || + (cs2 = apol_rule_type_to_str(rule_type2)) == NULL) { + return 0; + } + if ((compval = strcmp(cs1, cs2)) != 0) { + return compval; + } + + const qpol_type_t *t1, *t2; + const char *s1, *s2; + if (qpol_terule_get_source_type(q, r1, &t1) < 0 || + qpol_terule_get_source_type(q, r2, &t2) < 0) { + return 0; + } + if (qpol_type_get_name(q, t1, &s1) < 0 || + qpol_type_get_name(q, t2, &s2) < 0) { + return 0; + } + if ((compval = strcmp(s1, s2)) != 0) { + return compval; + } + + if (qpol_terule_get_target_type(q, r1, &t1) < 0 || + qpol_terule_get_target_type(q, r2, &t2) < 0) { + return 0; + } + if (qpol_type_get_name(q, t1, &s1) < 0 || + qpol_type_get_name(q, t2, &s2) < 0) { + return 0; + } + if ((compval = strcmp(s1, s2)) != 0) { + return compval; + } + + const qpol_class_t *c1, *c2; + if (qpol_terule_get_object_class(q, r1, &c1) < 0 || + qpol_terule_get_object_class(q, r2, &c2) < 0) { + return 0; + } + if (qpol_class_get_name(q, c1, &s1) < 0 || + qpol_class_get_name(q, c2, &s2) < 0) { + return 0; + } + return strcmp(s1, s2); + } + + /** + * Sort a vector of qpol_terule_t, sorting by rule type, then + * source type, then target type, and then by object class. + */ + void apol_tcl_terule_sort(apol_policy_t *policy, apol_vector_t *v) { + if (policy != NULL && v != NULL) { + apol_vector_sort(v, terule_sort, policy); + } + } + + /** + * Returns the policy version number for the currently opened + * policy. If the policy is modular, return the maximum + * allowed policy as per libsepol. + */ + unsigned int apol_tcl_get_policy_version(apol_policy_t *policy) { + if (policy == NULL) { + SWIG_exception(SWIG_RuntimeError, "No policy opened"); + } + if (apol_policy_get_policy_type(policy) != QPOL_POLICY_MODULE_BINARY) { + unsigned int version; + if (qpol_policy_get_policy_version(apol_policy_get_qpol(policy), &version) < 0) { + SWIG_exception(SWIG_RuntimeError, "Could not get policy version"); + } + return version; + } else { + return (unsigned int) SEPOL_POLICY_VERSION_MAX; + } + fail: + return 0; + } + + char *apol_tcl_get_error_string(void) { + return tcl_get_error(); + } +%} + +%rename(apol_tcl_rule_render) apol_tcl_avrule_render; +%rename(apol_tcl_rule_render) apol_tcl_terule_render; +%rename(apol_tcl_rule_render) apol_tcl_syn_avrule_render; +%rename(apol_tcl_rule_render) apol_tcl_syn_terule_render; + +/* Because this SWIG file will be written as C++, it expects all + * %newobject objects to be allocated via new and destructed with + * delete. However, the libapol render functions use malloc()/free() + * as that they come from C. Therefore, use an intermediate function + * to create a new string from the malloc() copy. + */ +%{ + static char *apol_tcl_malloc_to_new(char *s) { + if (s == NULL) { + return new char[0]; + } + char *t = new char[strlen(s) + 1]; + strcpy(t, s); + free(s); + return t; + } + char *apol_tcl_avrule_render(apol_policy_t *policy, qpol_avrule_t *rule) { + return apol_tcl_malloc_to_new(apol_avrule_render(policy, rule)); + } + char *apol_tcl_terule_render(apol_policy_t *policy, qpol_terule_t *rule) { + return apol_tcl_malloc_to_new(apol_terule_render(policy, rule)); + } + char *apol_tcl_syn_avrule_render(apol_policy_t *policy, qpol_syn_avrule_t *rule) { + return apol_tcl_malloc_to_new(apol_syn_avrule_render(policy, rule)); + } + + char *apol_tcl_syn_terule_render(apol_policy_t *policy, qpol_syn_terule_t *rule) { + return apol_tcl_malloc_to_new(apol_syn_terule_render(policy, rule)); + } +%} +%newobject apol_tcl_avrule_render(apol_policy_t *policy, qpol_avrule_t *rule); +char *apol_tcl_avrule_render(apol_policy_t *policy, qpol_avrule_t *rule); +%newobject apol_tcl_terule_render(apol_policy_t *policy, qpol_terule_t *rule); +char *apol_tcl_terule_render(apol_policy_t *policy, qpol_terule_t *rule); +%newobject apol_tcl_syn_avrule_render(apol_policy_t *policy, qpol_syn_avrule_t *rule); +char *apol_tcl_syn_avrule_render(apol_policy_t *policy, qpol_syn_avrule_t *rule); +%newobject apol_tcl_syn_terule_render(apol_policy_t *policy, qpol_syn_terule_t *rule); +char *apol_tcl_syn_terule_render(apol_policy_t *policy, qpol_syn_terule_t *rule); + + +void apol_tcl_avrule_sort(apol_policy_t *policy, apol_vector_t *v); +void apol_tcl_terule_sort(apol_policy_t *policy, apol_vector_t *v); +unsigned int apol_tcl_get_policy_version(apol_policy_t *policy); +char *apol_tcl_get_error_string(void); + +%{ + /** + * Open a sefs database from file. + * + * @param filename Database's filename. + */ + sefs_db *apol_tcl_open_database(const char * filename, Tcl_Interp * interp) + { + try { + return new sefs_db(filename, apol_tcl_route_sefs_to_string, interp); + } + catch (...) { + return NULL; + } + } + + /** + * Construct an in-memory database from part of a filesystem. + * + * @param filename Starting root directory. + */ + sefs_db *apol_tcl_open_database_from_dir(const char * filename, Tcl_Interp * interp) + { + sefs_filesystem *fs = NULL; + sefs_db *db = NULL; + try { + fs = new sefs_filesystem(filename, apol_tcl_route_sefs_to_string, interp); + db = new sefs_db(fs, apol_tcl_route_sefs_to_string, interp); + } + catch (...) { + delete fs; + delete db; + return NULL; + } + delete fs; + return db; + } + + struct apol_tcl_query_data { + Tcl_Interp *interp; + size_t matches; + }; + + static int apol_tcl_query_callback(sefs_fclist *fclist, const sefs_entry *entry, void *arg) { + struct apol_tcl_query_data *a = static_cast(arg); + Tcl_Interp *interp = a->interp; + Tcl_Obj *cmd[2]; + cmd[0] = Tcl_NewStringObj("Apol_File_Contexts::_search_callback", -1); + cmd[1] = SWIG_NewInstanceObj(SWIG_as_voidptr(entry), SWIGTYPE_p_sefs_entry, 0); + Tcl_EvalObjv(interp, 2, cmd, 0); + int retval = static_cast(++(a->matches)); + if (retval % 1000 == 0) { + SEFS_INFO(fclist, "Found %d results", retval); + } + return retval; + } + + int apol_tcl_query_database(sefs_fclist *fclist, sefs_query *query, Tcl_Interp * interp) + { + struct apol_tcl_query_data a = {interp, 0}; + int retval = fclist->runQueryMap(query, apol_tcl_query_callback, &a); + if (retval >= 0) { + tcl_clear_error(); + } + return retval; + } + + /** + * Include this function to force the generated SWIG wrapper + * to also include the code to convert from a Tcl object to a + * sefs_entry pointer; that code is used by + * apol_tcl_query_callback(). + */ + void apol_tcl_entry_do_nothing(sefs_entry *e) { + } +%} + + +/* Major hackery here to pass in the Tcl interpreter object as + * sefs_db's callback argument. This is needed so that the callback + * can properly update apol's progress dialog without deadlocking + * itself. + */ +%typemap (in) (const char * filename, Tcl_Interp *interp) { + $1 = Tcl_GetString($input); + $2 = interp; +}; +/* More hackery to have a callback function for running queries + * against a sefs_db. + */ +%typemap (in) (sefs_query * query, Tcl_Interp *interp) { + int res = SWIG_ConvertPtr($input, SWIG_as_voidptrptr(&$1), $1_descriptor, 0); + if (res) { + SWIG_exception_fail(SWIG_ArgError(res), "in method '" "apol_tcl_query_database" "', argument " "1"" of type '" "sefs_query *""'"); + } + $2 = interp; +}; +sefs_db *apol_tcl_open_database(const char * filename, Tcl_Interp * interp); +sefs_db *apol_tcl_open_database_from_dir(const char * filename, Tcl_Interp * interp); +%newobject apol_tcl_open_database(const char*, Tcl_Interp*); +%newobject apol_tcl_open_database_from_dir(const char*, Tcl_Interp*); +int apol_tcl_query_database(sefs_fclist *fclist, sefs_query *query, Tcl_Interp * interp) throw (std::invalid_argument, std::runtime_error); +void apol_tcl_entry_do_nothing(sefs_entry *e); + +// disable the exception handler, otherwise it will delete the error +// message when this function gets called +%exception; +extern void apol_tcl_clear_info_string(void); +extern int apol_tcl_get_info_level(void); +extern char *apol_tcl_get_info_string(void); +extern void apol_tcl_set_info_string(apol_policy_t *p, const char *s); + +// vim:ft=c noexpandtab -- cgit