summaryrefslogtreecommitdiffstats
path: root/apol/apol_tcl.i
diff options
context:
space:
mode:
Diffstat (limited to 'apol/apol_tcl.i')
-rw-r--r--apol/apol_tcl.i451
1 files changed, 451 insertions, 0 deletions
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 <config.h>
+
+#include <apol/avrule-query.h>
+#include <apol/terule-query.h>
+#include <apol/policy.h>
+#include <apol/policy-path.h>
+#include <apol/util.h>
+#include <sefs/db.hh>
+#include <sefs/filesystem.hh>
+#include <sefs/fcfile.hh>
+%}
+
+%{
+/* 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<const qpol_avrule_t *>(a);
+ const qpol_avrule_t *r2 = static_cast<const qpol_avrule_t *>(b);
+ apol_policy_t *p = static_cast<apol_policy_t *>(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<const qpol_terule_t *>(a);
+ const qpol_terule_t *r2 = static_cast<const qpol_terule_t *>(b);
+ apol_policy_t *p = static_cast<apol_policy_t *>(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<struct apol_tcl_query_data *>(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<int>(++(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