summaryrefslogtreecommitdiffstats
path: root/libqpol
diff options
context:
space:
mode:
Diffstat (limited to 'libqpol')
-rw-r--r--libqpol/Makefile.am8
-rw-r--r--libqpol/include/Makefile.am1
-rw-r--r--libqpol/include/qpol/Makefile.am30
-rw-r--r--libqpol/include/qpol/avrule_query.h167
-rw-r--r--libqpol/include/qpol/bool_query.h127
-rw-r--r--libqpol/include/qpol/class_perm_query.h209
-rw-r--r--libqpol/include/qpol/cond_query.h198
-rw-r--r--libqpol/include/qpol/constraint_query.h262
-rw-r--r--libqpol/include/qpol/context_query.h93
-rw-r--r--libqpol/include/qpol/fs_use_query.h115
-rw-r--r--libqpol/include/qpol/genfscon_query.h128
-rw-r--r--libqpol/include/qpol/isid_query.h91
-rw-r--r--libqpol/include/qpol/iterator.h95
-rw-r--r--libqpol/include/qpol/mls_query.h260
-rw-r--r--libqpol/include/qpol/mlsrule_query.h104
-rw-r--r--libqpol/include/qpol/module.h125
-rw-r--r--libqpol/include/qpol/netifcon_query.h104
-rw-r--r--libqpol/include/qpol/nodecon_query.h132
-rw-r--r--libqpol/include/qpol/permissive_query.h68
-rw-r--r--libqpol/include/qpol/polcap_query.h68
-rw-r--r--libqpol/include/qpol/policy.h261
-rw-r--r--libqpol/include/qpol/policy_extend.h86
-rw-r--r--libqpol/include/qpol/portcon_query.h118
-rw-r--r--libqpol/include/qpol/rbacrule_query.h130
-rw-r--r--libqpol/include/qpol/role_query.h119
-rw-r--r--libqpol/include/qpol/syn_rule_query.h314
-rw-r--r--libqpol/include/qpol/terule_query.h159
-rw-r--r--libqpol/include/qpol/type_query.h175
-rw-r--r--libqpol/include/qpol/user_query.h130
-rw-r--r--libqpol/include/qpol/util.h61
-rw-r--r--libqpol/src/Makefile.am89
-rw-r--r--libqpol/src/avrule_query.c288
-rw-r--r--libqpol/src/bool_query.c193
-rw-r--r--libqpol/src/class_perm_query.c653
-rw-r--r--libqpol/src/cond_query.c620
-rw-r--r--libqpol/src/constraint_query.c983
-rw-r--r--libqpol/src/context_query.c123
-rw-r--r--libqpol/src/expand.c190
-rw-r--r--libqpol/src/expand.h51
-rw-r--r--libqpol/src/fs_use_query.c167
-rw-r--r--libqpol/src/genfscon_query.c294
-rw-r--r--libqpol/src/isid_query.c139
-rw-r--r--libqpol/src/iterator.c797
-rw-r--r--libqpol/src/iterator_internal.h123
-rw-r--r--libqpol/src/libqpol.map73
-rw-r--r--libqpol/src/mls_query.c639
-rw-r--r--libqpol/src/mlsrule_query.c230
-rw-r--r--libqpol/src/module.c236
-rw-r--r--libqpol/src/module_compiler.c1440
-rw-r--r--libqpol/src/module_compiler.h115
-rw-r--r--libqpol/src/netifcon_query.c159
-rw-r--r--libqpol/src/nodecon_query.c329
-rw-r--r--libqpol/src/permissive_query.c95
-rw-r--r--libqpol/src/polcap_query.c92
-rw-r--r--libqpol/src/policy.c1563
-rw-r--r--libqpol/src/policy_define.c4319
-rw-r--r--libqpol/src/policy_define.h75
-rw-r--r--libqpol/src/policy_extend.c1397
-rw-r--r--libqpol/src/policy_parse.y834
-rw-r--r--libqpol/src/policy_scan.l320
-rw-r--r--libqpol/src/portcon_query.c183
-rw-r--r--libqpol/src/qpol_internal.h122
-rw-r--r--libqpol/src/queue.c183
-rw-r--r--libqpol/src/queue.h67
-rw-r--r--libqpol/src/rbacrule_query.c358
-rw-r--r--libqpol/src/role_query.c238
-rw-r--r--libqpol/src/syn_rule_internal.h47
-rw-r--r--libqpol/src/syn_rule_query.c782
-rw-r--r--libqpol/src/terule_query.c264
-rw-r--r--libqpol/src/type_query.c468
-rw-r--r--libqpol/src/user_query.c224
-rw-r--r--libqpol/src/util.c231
-rw-r--r--libqpol/swig/Makefile.am15
-rw-r--r--libqpol/swig/java/MANIFEST.MF.in9
-rw-r--r--libqpol/swig/java/Makefile.am97
-rw-r--r--libqpol/swig/python/Makefile.am34
-rw-r--r--libqpol/swig/python/__init__.py1
-rw-r--r--libqpol/swig/qpol.i2879
-rw-r--r--libqpol/swig/tcl/Makefile.am35
-rw-r--r--libqpol/tests/Makefile.am17
-rw-r--r--libqpol/tests/capabilities-tests.c542
-rw-r--r--libqpol/tests/capabilities-tests.h35
-rw-r--r--libqpol/tests/iterators-tests.c87
-rw-r--r--libqpol/tests/iterators-tests.h35
-rw-r--r--libqpol/tests/libqpol-tests.c57
-rw-r--r--libqpol/tests/policy-features-tests.c145
-rw-r--r--libqpol/tests/policy-features-tests.h35
87 files changed, 27754 insertions, 0 deletions
diff --git a/libqpol/Makefile.am b/libqpol/Makefile.am
new file mode 100644
index 0000000..49afe65
--- /dev/null
+++ b/libqpol/Makefile.am
@@ -0,0 +1,8 @@
+if DO_SWIGIFY
+ MAYBE_SWIG = swig
+endif
+
+SUBDIRS = src include tests $(MAYBE_SWIG)
+
+libqpol.a libqpol.so:
+ $(MAKE) -C src $@
diff --git a/libqpol/include/Makefile.am b/libqpol/include/Makefile.am
new file mode 100644
index 0000000..e90a0d4
--- /dev/null
+++ b/libqpol/include/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = qpol
diff --git a/libqpol/include/qpol/Makefile.am b/libqpol/include/qpol/Makefile.am
new file mode 100644
index 0000000..b55acb7
--- /dev/null
+++ b/libqpol/include/qpol/Makefile.am
@@ -0,0 +1,30 @@
+qpoldir = $(includedir)/qpol
+
+qpol_HEADERS = \
+ avrule_query.h \
+ bool_query.h \
+ class_perm_query.h \
+ cond_query.h \
+ constraint_query.h \
+ context_query.h \
+ fs_use_query.h \
+ genfscon_query.h \
+ isid_query.h \
+ iterator.h \
+ mls_query.h \
+ mlsrule_query.h \
+ module.h \
+ netifcon_query.h \
+ nodecon_query.h \
+ permissive_query.h \
+ polcap_query.h \
+ policy.h \
+ policy_extend.h \
+ portcon_query.h \
+ rbacrule_query.h \
+ role_query.h \
+ syn_rule_query.h \
+ terule_query.h \
+ type_query.h \
+ user_query.h \
+ util.h
diff --git a/libqpol/include/qpol/avrule_query.h b/libqpol/include/qpol/avrule_query.h
new file mode 100644
index 0000000..d9050d2
--- /dev/null
+++ b/libqpol/include/qpol/avrule_query.h
@@ -0,0 +1,167 @@
+ /**
+ * @file
+ * Defines the public interface for searching and iterating over avrules.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @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
+ */
+
+#ifndef QPOL_AVRULE_QUERY_H
+#define QPOL_AVRULE_QUERY_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <qpol/policy.h>
+#include <qpol/class_perm_query.h>
+#include <qpol/cond_query.h>
+#include <qpol/type_query.h>
+
+ typedef struct qpol_avrule qpol_avrule_t;
+
+/* rule type defines (values copied from "sepol/policydb/policydb.h") */
+#define QPOL_RULE_ALLOW 1
+#define QPOL_RULE_NEVERALLOW 128
+#define QPOL_RULE_AUDITALLOW 2
+/* dontaudit is actually stored as auditdeny so that value is used here */
+#define QPOL_RULE_DONTAUDIT 4
+
+/**
+ * Get an iterator over all av rules in a policy of a rule type in
+ * rule_type_mask. It is an error to call this function if rules are
+ * not loaded. Likewise, it is an error if neverallows are requested
+ * but they were not loaded.
+ * @param policy Policy from which to get the av rules.
+ * @param rule_type_mask Bitwise or'ed set of QPOL_RULE_* values.
+ * It is an error to specify any of QPOL_RULE_TYPE_* in the mask.
+ * @param iter Iterator over items of type qpol_avrule_t returned.
+ * The caller is responsible for calling qpol_iterator_destroy()
+ * to free memory used by this iterator.
+ * It is important to note that this iterator is only valid as long as
+ * the policy is unmodifed.
+ * @returm 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *iter will be NULL.
+ */
+ extern int qpol_policy_get_avrule_iter(const qpol_policy_t * policy, uint32_t rule_type_mask, qpol_iterator_t ** iter);
+
+/**
+ * Get the source type from an av rule.
+ * @param policy Policy from which the rule comes.
+ * @param rule The rule from which to get the source type.
+ * @param source Pointer in which to store the source type.
+ * The caller should not free this pointer.
+ * @returm 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *source will be NULL.
+ */
+ extern int qpol_avrule_get_source_type(const qpol_policy_t * policy, const qpol_avrule_t * rule,
+ const qpol_type_t ** source);
+
+/**
+ * Get the target type from an av rule.
+ * @param policy Policy from which the rule comes.
+ * @param rule The rule from which to get the target type.
+ * @param target Pointer in which to store the target type.
+ * The caller should not free this pointer.
+ * @returm 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *target will be NULL.
+ */
+ extern int qpol_avrule_get_target_type(const qpol_policy_t * policy, const qpol_avrule_t * rule,
+ const qpol_type_t ** target);
+
+/**
+ * Get the object class from an av rule.
+ * @param policy Policy from which the rule comes.
+ * @param rule The rule from which to get the object class.
+ * @param obj_class Pointer in which to store the object class.
+ * The caller should not free this pointer.
+ * @returm 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *obj_class will be NULL.
+ */
+ extern int qpol_avrule_get_object_class(const qpol_policy_t * policy, const qpol_avrule_t * rule,
+ const qpol_class_t ** obj_class);
+
+/**
+ * Get an iterator over the permissions in an av rule.
+ * @param policy Policy from which the rule comes.
+ * @param rule The rule from which to get the permissions.
+ * @param perms Iterator over items of type char* returned.
+ * The caller is responsible for calling qpol_iterator_destroy()
+ * to free memory used by this iterator. The caller <b>should call</b>
+ * <b>free() on the strings returned by qpol_iterator_get_item().</b>
+ * It is important to note that this iterator is only valid as long as
+ * the policy is unmodifed.
+ * @returm 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *perms will be NULL.
+ */
+ extern int qpol_avrule_get_perm_iter(const qpol_policy_t * policy, const qpol_avrule_t * rule, qpol_iterator_t ** perms);
+
+/**
+ * Get the rule type value for an av rule.
+ * @param policy Policy from which the rule comes.
+ * @param rule The rule from which to get the rule type.
+ * @param rule_type Integer in which to store the rule type value.
+ * The value will be one of the QPOL_RULE_* values above.
+ * @returm 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *rule_type will be 0.
+ */
+ extern int qpol_avrule_get_rule_type(const qpol_policy_t * policy, const qpol_avrule_t * rule, uint32_t * rule_type);
+
+/**
+ * Get the conditional from which an av rule comes. If the rule
+ * is not a conditional rule *cond is set to NULL.
+ * @param policy Policy from which the rule comes.
+ * @param rule The rule from which to get the conditional.
+ * @param cond The conditional returned. (NULL if rule is not conditional)
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *cond will be NULL. If the rule is not conditional
+ * *cond is set to NULL and the function is considered successful.
+ */
+ extern int qpol_avrule_get_cond(const qpol_policy_t * policy, const qpol_avrule_t * rule, const qpol_cond_t ** cond);
+
+/**
+ * Determine if a rule is enabled. Unconditional rules are always enabled.
+ * @param policy Policy from which the rule comes.
+ * @param rule The rule to check.
+ * @param is_enabled Integer in which to store the result: set to 1 if enabled
+ * and 0 otherwise.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *is_enabled will be 0.
+ */
+ extern int qpol_avrule_get_is_enabled(const qpol_policy_t * policy, const qpol_avrule_t * rule, uint32_t * is_enabled);
+
+/**
+ * Get the list (true or false) in which a conditional rule is. It is
+ * an error to call this function for an unconditional rule.
+ * @param policy Policy from which the rule comes.
+ * @param rule The rule to check.
+ * @param which_list Integer in which to store the result: set to 1 if
+ * rule is in the true list or 0 if in the false list.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *which_list will be 0.
+ */
+ extern int qpol_avrule_get_which_list(const qpol_policy_t * policy, const qpol_avrule_t * rule, uint32_t * which_list);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libqpol/include/qpol/bool_query.h b/libqpol/include/qpol/bool_query.h
new file mode 100644
index 0000000..41c2d26
--- /dev/null
+++ b/libqpol/include/qpol/bool_query.h
@@ -0,0 +1,127 @@
+/**
+ * @file
+ * Defines the public interface for searching and iterating over booleans.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @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
+ */
+
+#ifndef QPOL_BOOL_QUERY_H
+#define QPOL_BOOL_QUERY_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stddef.h>
+#include <stdint.h>
+#include <qpol/policy.h>
+#include <qpol/iterator.h>
+
+ typedef struct qpol_bool qpol_bool_t;
+
+/**
+ * Get the datum for a conditional boolean by name.
+ * @param policy The policy database from which to retrieve the boolean.
+ * @param name The name of the boolean; searching is case sensitive.
+ * @param datum Pointer to set to the boolean's datum entry in the policy.
+ * This memory should not be freed by the user.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *datum will be NULL.
+ */
+ extern int qpol_policy_get_bool_by_name(const qpol_policy_t * policy, const char *name, qpol_bool_t ** datum);
+
+/**
+ * Get an iterator for conditional booleans in the policy.
+ * @param policy The policy database from which to create the iterator.
+ * @param iter Iterator of type qpol_bool_t* returned;
+ * the user is responsible for calling qpol_iterator_destroy to
+ * free memory used. It is also important to note that an iterator
+ * is only valid as long as the policy is unchanged.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *iter will be NULL.
+ */
+ extern int qpol_policy_get_bool_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter);
+
+/**
+ * Get the integer value associated with a boolean. Values range from 1 to
+ * the number of conditional booleans declared in the policy.
+ * @param policy The policy with which the boolean is associated.
+ * @param datum Boolean datum from which to get the value. Must be non-NULL.
+ * @param value Pointer to integer be set to value. Must be non-NULL.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *value will be 0.
+ */
+ extern int qpol_bool_get_value(const qpol_policy_t * policy, const qpol_bool_t * datum, uint32_t * value);
+
+/**
+ * Get the state of a boolean.
+ * @param policy The policy with which the boolean is associated.
+ * @param datum Boolean datum from which to get the state. Must be non-NULL.
+ * @param state Pointer to the integer to be set to the boolean's state.
+ * Must be non-NULL.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *state will set to 0 (false).
+ */
+ extern int qpol_bool_get_state(const qpol_policy_t * policy, const qpol_bool_t * datum, int *state);
+
+/**
+ * Set the state of a boolean and update the state of all conditionals
+ * using the boolean.
+ * @param policy The policy with which the boolean is associated.
+ * The state of the policy is changed by this function.
+ * @param datum Boolean datum for which to set the state. Must be non-NULL.
+ * @param state Value to which to set the state of the boolean.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set.
+ */
+ extern int qpol_bool_set_state(qpol_policy_t * policy, qpol_bool_t * datum, int state);
+
+/**
+ * Set the state of a boolean but do not update the state of all conditionals
+ * using the boolean. The caller is responsible for calling
+ * qpol_policy_reevaluate_conds() at a later time to maintain a consistent
+ * state of conditional expressions.
+ * @param policy The policy with which the boolean is associated.
+ * The state of the policy is changed by this function.
+ * @param datum Boolean datum for which to set the state. Must be non-NULL.
+ * @param state Value to which to set the state of the boolean.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set.
+ */
+ extern int qpol_bool_set_state_no_eval(qpol_policy_t * policy, qpol_bool_t * datum, int state);
+
+/**
+ * Get the name which identifies a boolean from its datum.
+ * @param policy The policy with which the boolean is associated.
+ * @param datum Boolean datum for which to get the name. Must be non-NULL.
+ * @param name Pointer to the string in which to store the name.
+ * Must be non-NULL. The caller should not free the string.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *name will be NULL.
+ */
+ extern int qpol_bool_get_name(const qpol_policy_t * policy, const qpol_bool_t * datum, const char **name);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* QPOL_BOOL_QUERY_H */
diff --git a/libqpol/include/qpol/class_perm_query.h b/libqpol/include/qpol/class_perm_query.h
new file mode 100644
index 0000000..a74357a
--- /dev/null
+++ b/libqpol/include/qpol/class_perm_query.h
@@ -0,0 +1,209 @@
+/**
+ * @file
+ * Defines the public interface for searching and iterating over
+ * classes, commons, and permissions.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @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
+ */
+
+#ifndef QPOL_CLASS_PERM_QUERY_H
+#define QPOL_CLASS_PERM_QUERY_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stddef.h>
+#include <stdint.h>
+#include <qpol/iterator.h>
+#include <qpol/policy.h>
+
+ typedef struct qpol_class qpol_class_t;
+ typedef struct qpol_common qpol_common_t;
+
+/* perms */
+/**
+ * Get an iterator over the set of classes which contain a permission
+ * with the name perm. This function does not search for the permission
+ * in the class's inherited common.
+ * @param policy The policy from which to query the classes.
+ * @param perm The name of the permission to be matched. Must be non-NULL.
+ * @param classes The iterator of type qpol_class_t returned;
+ * the user is responsible for calling qpol_iterator_destroy
+ * to free memory used. It is also important to note
+ * that an iterator is only valid as long as the policy is unchanged.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *classes will be NULL;
+ */
+ extern int qpol_perm_get_class_iter(const qpol_policy_t * policy, const char *perm, qpol_iterator_t ** classes);
+
+/**
+ * Get an iterator over the set of commons which contain a permission
+ * with the name perm.
+ * @param policy The policy from which to query the commons.
+ * @param perm The name of the permission to be matched. Must be non-NULL.
+ * @param commons The iterator of type qpol_common_t returned;
+ * the user is responsible for calling qpol_iterator_destroy
+ * to free memory used. It is also important to note
+ * that an iterator is only valid as long as the policy is unchanged.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *commons will be NULL;
+ */
+ extern int qpol_perm_get_common_iter(const qpol_policy_t * policy, const char *perm, qpol_iterator_t ** commons);
+
+/* classes */
+/**
+ * Get an object class by name.
+ * @param policy The policy from which to get the class.
+ * @param name The name of the class; searching is case sensitive.
+ * @param obj_class Pointer in which to store the class.
+ * Caller should not free this pointer.
+ * @return Returns 0 for success and < 0 for failure; if the call fails,
+ * errno will be set and *obj_class will be NULL;
+ */
+ extern int qpol_policy_get_class_by_name(const qpol_policy_t * policy, const char *name, const qpol_class_t ** obj_class);
+
+/**
+ * Get an iterator for object classes in the policy.
+ * @param policy The policy database from which to create the iterator.
+ * @param iter Iterator of type qpol_class_t* returned; the user
+ * is responsible for calling qpol_iterator_destroy to free memory used.
+ * It is also important to note that an iterator is only valid as long
+ * as the policy is unchanged.
+ * @return Returns 0 for success and < 0 for failure; if the call fails,
+ * errno will be set and *iter will be NULL.
+*/
+ extern int qpol_policy_get_class_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter);
+
+/**
+ * Get the integer value associated with a class. Values range from 1 to
+ * the number of object classes declared in the policy.
+ * @param policy The policy with which the class is associated.
+ * @param obj_class Class from which to get the value. Must be non-NULL.
+ * @param value Pointer to the integer to be set to value. Must be non-NULL.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *value will be 0.
+ */
+ extern int qpol_class_get_value(const qpol_policy_t * policy, const qpol_class_t * obj_class, uint32_t * value);
+
+/**
+ * Get the common used by a class.
+ * @param policy The policy with which the class is associated.
+ * @param obj_class Class from which to get the value. Must be non-NULL.
+ * @param common Pointer to the common associated with this
+ * class; the caller should not free this pointer. Not all classes have an
+ * associated common so it is possible for *common to be NULL on success.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *common will be NULL.
+ */
+ extern int qpol_class_get_common(const qpol_policy_t * policy, const qpol_class_t * obj_class,
+ const qpol_common_t ** common);
+
+/**
+ * Get an iterator for the set of (unique) permissions for a class.
+ * @param policy The policy with which the class is associated.
+ * @param obj_class The class from which to get the permissions.
+ * @param perms Iterator of type char* returned for the list of
+ * permissions for this class. The list only contains permissions unique
+ * to the class not those included from a common. The iterator is only
+ * valid as long as the policy is unchanged; the caller is responsible
+ * for calling qpol_iterator_destroy to free memory used.
+ * @return Returns 0 for success and < 0 for failure; if the call fails,
+ * errno will be set and *perms will be NULL.
+ */
+ extern int qpol_class_get_perm_iter(const qpol_policy_t * policy, const qpol_class_t * obj_class, qpol_iterator_t ** perms);
+
+/**
+ * Get the name which identifies a class.
+ * @param policy The policy with which the class is associated.
+ * @param datum Class for which to get the name. Must be non-NULL.
+ * @param name Pointer to the string in which to store the name.
+ * Must be non-NULL. Caller should not free the string.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *name will be NULL.
+ */
+ extern int qpol_class_get_name(const qpol_policy_t * policy, const qpol_class_t * obj_class, const char **name);
+
+/* commons */
+/**
+ * Get a common by name.
+ * @param policy from which to get the common.
+ * @param name The name of the common; searching is case sensitive.
+ * @param common Pointer in which to store the common.
+ * Caller should not free this pointer.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *common will be NULL.
+ */
+ extern int qpol_policy_get_common_by_name(const qpol_policy_t * policy, const char *name, const qpol_common_t ** common);
+
+/**
+ * Get an iterator for commons in the policy
+ * @param policy The policy from which to create the iterator.
+ * @param iter Iterator of type qpol_common_t* returned;
+ * the user is responsible for calling qpol_iterator_destroy to
+ * free memory used. It is also important to note that an iterator is
+ * only valid as long as the policy is unchanged.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *iter will be NULL.
+ */
+ extern int qpol_policy_get_common_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter);
+
+/**
+ * Get the integer value associated with a common. Values range from 1 to
+ * the number of commons declared in the policy.
+ * @param policy The policy associated with the common.
+ * @param common The common from which to get the value.
+ * @param value Pointer to the integer to be set to value. Must be non-NULL.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *value will be 0.
+ */
+ extern int qpol_common_get_value(const qpol_policy_t * policy, const qpol_common_t * common, uint32_t * value);
+
+/**
+ * Get an iterator for the permissions included in a common.
+ * @param policy The policy associated with the common.
+ * @param common The common from which to get permissions.
+ * @param perms Iterator of type char* returned for the list of
+ * permissions for this common. The iterator is only valid as long
+ * as the policy is unchanged; the caller is responsible for calling
+ * qpol_iterator_destroy to free memory used.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *perms will be NULL.
+ */
+ extern int qpol_common_get_perm_iter(const qpol_policy_t * policy, const qpol_common_t * common, qpol_iterator_t ** perms);
+
+/**
+ * Get the name which identifies a common.
+ * @param policy associated with the common.
+ * @param common The common from which to get the name.
+ * @param name Pointer in which to store the name. Must be non-NULL;
+ * the caller should not free the string.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *name will be NULL.
+ */
+ extern int qpol_common_get_name(const qpol_policy_t * policy, const qpol_common_t * common, const char **name);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* QPOL_CLASS_PERM_QUERY_H */
diff --git a/libqpol/include/qpol/cond_query.h b/libqpol/include/qpol/cond_query.h
new file mode 100644
index 0000000..e2722ef
--- /dev/null
+++ b/libqpol/include/qpol/cond_query.h
@@ -0,0 +1,198 @@
+/**
+ * @file
+ * Defines the public interface for searching and iterating over
+ * conditionals
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @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
+ */
+
+#ifndef QPOL_COND_QUERY_H
+#define QPOL_COND_QUERY_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <qpol/policy.h>
+#include <qpol/bool_query.h>
+#include <qpol/iterator.h>
+
+ typedef struct qpol_cond qpol_cond_t;
+ typedef struct qpol_cond_expr_node qpol_cond_expr_node_t;
+
+/**
+ * Get an iterator over all conditionals in a policy.
+ * It is an error to call this function if rules are not loaded.
+ * @param policy Policy from which to get the conditionals.
+ * @param iter Iterator over items of type qpol_cond_t returned.
+ * The caller is responsible for calling qpol_iterator_destroy()
+ * to free memory used in this iterator.
+ * It is important to node that this iterator is only valid as long as
+ * the policy is unmodified.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *iter will be NULL.
+ */
+ extern int qpol_policy_get_cond_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter);
+
+/**
+ * Get an iterator over the nodes in a conditional expression.
+ * Each node represents a single token of the expression in RPN.
+ * @param policy The policy associated with the conditional.
+ * @param cond The conditional from which to get the expression.
+ * @param iter Iterator over items of type qpol_cond_expr_node_t returned.
+ * The caller is responsible for calling qpol_iterator_destroy()
+ * to free memory used in this iterator.
+ * It is important to node that this iterator is only valid as long as
+ * the policy is unmodified.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *iter will be NULL.
+ */
+ extern int qpol_cond_get_expr_node_iter(const qpol_policy_t * policy, const qpol_cond_t * cond, qpol_iterator_t ** iter);
+
+/* flags for conditional rules */
+#define QPOL_COND_RULE_LIST 0x00000001
+#define QPOL_COND_RULE_ENABLED 0x00000002
+
+/**
+ * Get an iterator over all av rules in a conditional's true list
+ * of a rule type in rule_type_mask.
+ * @param policy The policy associated with the conditional.
+ * @param cond The conditional from which to get the rules.
+ * @param rule_type_mask Bitwise or'ed set of QPOL_RULE_* values
+ * (see avrule_query.h) to include.
+ * @param iter Iterator over items of type qpol_avrule_t returned.
+ * The caller is responsible for calling qpol_iterator_destroy()
+ * to free memory used by this iterator.
+ * It is important to note that this iterator is only valid as long as
+ * the policy is unmodifed.
+ * @returm 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *iter will be NULL.
+ */
+ extern int qpol_cond_get_av_true_iter(const qpol_policy_t * policy, const qpol_cond_t * cond, uint32_t rule_type_mask,
+ qpol_iterator_t ** iter);
+
+/**
+ * Get an iterator over all type rules in a conditional's true list
+ * of a rule type in rule_type_mask.
+ * @param policy The policy associated with the conditional.
+ * @param cond The conditional from which to get the rules.
+ * @param rule_type_mask Bitwise or'ed set of QPOL_RULE_TYPE_* values
+ * (see terule_query.h) to include.
+ * @param iter Iterator over items of type qpol_terule_t returned.
+ * The caller is responsible for calling qpol_iterator_destroy()
+ * to free memory used by this iterator.
+ * It is important to note that this iterator is only valid as long as
+ * the policy is unmodifed.
+ * @returm 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *iter will be NULL.
+ */
+ extern int qpol_cond_get_te_true_iter(const qpol_policy_t * policy, const qpol_cond_t * cond, uint32_t rule_type_mask,
+ qpol_iterator_t ** iter);
+
+/**
+ * Get an iterator over all av rules in a conditional's false list
+ * of a rule type in rule_type_mask.
+ * @param policy The policy associated with the conditional.
+ * @param cond The conditional from which to get the rules.
+ * @param rule_type_mask Bitwise or'ed set of QPOL_RULE_* values
+ * (see avrule_query.h) to include.
+ * @param iter Iterator over items of type qpol_avrule_t returned.
+ * The caller is responsible for calling qpol_iterator_destroy()
+ * to free memory used by this iterator.
+ * It is important to note that this iterator is only valid as long as
+ * the policy is unmodifed.
+ * @returm 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *iter will be NULL.
+ */
+ extern int qpol_cond_get_av_false_iter(const qpol_policy_t * policy, const qpol_cond_t * cond, uint32_t rule_type_mask,
+ qpol_iterator_t ** iter);
+
+/**
+ * Get an iterator over all type rules in a conditional's false list
+ * of a rule type in rule_type_mask.
+ * @param policy The policy associated with the conditional.
+ * @param cond The conditional from which to get the rules.
+ * @param rule_type_mask Bitwise or'ed set of QPOL_RULE_TYPE_* values
+ * (see terule_query.h) to include.
+ * @param iter Iterator over items of type qpol_avrule_t returned.
+ * The caller is responsible for calling qpol_iterator_destroy()
+ * to free memory used by this iterator.
+ * It is important to note that this iterator is only valid as long as
+ * the policy is unmodifed.
+ * @returm 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *iter will be NULL.
+ */
+ extern int qpol_cond_get_te_false_iter(const qpol_policy_t * policy, const qpol_cond_t * cond, uint32_t rule_type_mask,
+ qpol_iterator_t ** iter);
+
+/**
+ * Evaluate the expression of a conditional using current boolean values
+ * in the policy.
+ * @param policy The policy associated with the conditional.
+ * @param cond The conditional to evaluate.
+ * @param is_true Integer in which to store the result of evaluating the
+ * the expression, will be 1 if true and 0 otherwise.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *is_true will be 0.
+ */
+ extern int qpol_cond_eval(const qpol_policy_t * policy, const qpol_cond_t * cond, uint32_t * is_true);
+
+/* values identical to conditional.h in sepol */
+#define QPOL_COND_EXPR_BOOL 1 /* plain bool */
+#define QPOL_COND_EXPR_NOT 2 /* !bool */
+#define QPOL_COND_EXPR_OR 3 /* bool || bool */
+#define QPOL_COND_EXPR_AND 4 /* bool && bool */
+#define QPOL_COND_EXPR_XOR 5 /* bool ^ bool */
+#define QPOL_COND_EXPR_EQ 6 /* bool == bool */
+#define QPOL_COND_EXPR_NEQ 7 /* bool != bool */
+
+/**
+ * Get the type of an expression node.
+ * @param policy The policy associated with the conditional expression.
+ * @param node The node from which to get the expression type.
+ * @param expr_type Integer in which to store the expression type;
+ * the value will be one of QPOL_COND_EXPR_* above.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *expr_type will be 0.
+ */
+ extern int qpol_cond_expr_node_get_expr_type(const qpol_policy_t * policy, const qpol_cond_expr_node_t * node,
+ uint32_t * expr_type);
+
+/**
+ * Get the boolean used in an expression node. This is only valid
+ * when the node's expression type is QPOL_COND_EXPR_BOOL.
+ * @param policy The policy associated with the conditional experssion.
+ * @param node The node from which to get the boolean. It is an error
+ * to call this function if the node is not of type QPOL_COND_EXPR_BOOL.
+ * @param cond_bool Pointer in which to store the boolean.
+ * The caller should not free this pointer.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *cond_bool will be NULL.
+ */
+ extern int qpol_cond_expr_node_get_bool(const qpol_policy_t * policy, const qpol_cond_expr_node_t * node,
+ qpol_bool_t ** cond_bool);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* QPOL_COND_QUERY_H */
diff --git a/libqpol/include/qpol/constraint_query.h b/libqpol/include/qpol/constraint_query.h
new file mode 100644
index 0000000..f5cd7bf
--- /dev/null
+++ b/libqpol/include/qpol/constraint_query.h
@@ -0,0 +1,262 @@
+/**
+ * @file
+ * Defines the public interface for searching and iterating over
+ * constraints
+ *
+ * @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
+ */
+
+#ifndef QPOL_CONSTRAINT_QUERY_H
+#define QPOL_CONSTRAINT_QUERY_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <qpol/policy.h>
+#include <qpol/iterator.h>
+#include <qpol/class_perm_query.h>
+
+ typedef struct qpol_constraint qpol_constraint_t;
+ typedef struct qpol_validatetrans qpol_validatetrans_t;
+ typedef struct qpol_constraint_expr_node qpol_constraint_expr_node_t;
+
+/**
+ * Get an iterator for the constraints in a policy.
+ * @param policy The policy from which to create the iterator.
+ * @param iter Iterator over items of type qpol_constraint_t returned.
+ * The caller is responsible for calling qpol_iterator_destroy()
+ * to free memory used by this iterator. <b>The caller must also call free()
+ * on items returned by qpol_iterator_get_item() when using this iterator.</b>
+ * It is important to note that this iterator is only valid as long
+ * as the policy is unmodified.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *iter will be NULL.
+ */
+ extern int qpol_policy_get_constraint_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter);
+
+/**
+ * Get the object class from a constraint.
+ * @param policy The policy associated with the constraint.
+ * @param constr The constraint from which to get the class.
+ * @param obj_class Pointer in which to store the object class.
+ * The caller should not free this pointer.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *obj_class will be NULL.
+ */
+ extern int qpol_constraint_get_class(const qpol_policy_t * policy, const qpol_constraint_t * constr,
+ const qpol_class_t ** obj_class);
+
+/**
+ * Get an iterator over the permissions in a constraint.
+ * @param policy The policy from which the constraint comes.
+ * @param constr The constraint from which to get the permissions.
+ * @param iter Iterator over items of type char*.
+ * The caller is responsible for calling qpol_iterator_destroy()
+ * to free memory used by this iterator. The caller <b>should call</b>
+ * <b>free() on the strings returned by qpol_iterator_get_item().</b>
+ * It is important to note that this iterator is only valid as long
+ * as the policy is unmodified.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *iter will be NULL.
+ */
+ extern int qpol_constraint_get_perm_iter(const qpol_policy_t * policy, const qpol_constraint_t * constr,
+ qpol_iterator_t ** iter);
+
+/**
+ * Get an iterator over the nodes in a constraint expression.
+ * @param policy The policy from which the constraint comes.
+ * @param constr The constraint from which to get the expression.
+ * @param iter Iterator over items of type qpol_constraint_expr_node_t.
+ * The caller is responsible for calling qpol_iterator_destroy()
+ * to free memory used by this iterator. The caller should not
+ * free the items returned by qpol_iterator_get_item().
+ * It is important to note that this iterator is only valid as long
+ * as the policy is unmodified.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *iter will be NULL.
+ */
+ extern int qpol_constraint_get_expr_iter(const qpol_policy_t * policy, const qpol_constraint_t * constr,
+ qpol_iterator_t ** iter);
+
+/**
+ * Get an iterator for the validatetrans statements in a policy.
+ * @param policy The policy from which to create the iterator.
+ * @param iter Iterator over items of type qpol_validatetrans_t returned.
+ * The caller is responsible for calling qpol_iterator_destroy()
+ * to free memory used by this iterator. <b>The caller must also call free()
+ * on items returned by qpol_iterator_get_item() when using this iterator.</b>
+ * It is important to note that this iterator is only valid as long
+ * as the policy is unmodified.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *iter will be NULL.
+ */
+ extern int qpol_policy_get_validatetrans_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter);
+
+/**
+ * Get the object class from a validatetrans statement.
+ * @param policy The policy associated with the validatetrans statement.
+ * @param vtrans The validatetrans statement from which to get the class.
+ * @param obj_class Pointer in which to store the object class.
+ * The caller should not free this pointer.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *obj_class will be NULL.
+ */
+ extern int qpol_validatetrans_get_class(const qpol_policy_t * policy, const qpol_validatetrans_t * vtrans,
+ const qpol_class_t ** obj_class);
+
+/**
+ * Get an iterator over the nodes in a validatetrans expression.
+ * @param policy The policy from which the validatetrans statement comes.
+ * @param vtrans The validatetrans statement from which to get the expression.
+ * @param iter Iterator over items of type qpol_constraint_expr_node_t.
+ * The caller is responsible for calling qpol_iterator_destroy()
+ * to free memory used by this iterator. The caller should not
+ * free the items returned by qpol_iterator_get_item().
+ * It is important to note that this iterator is only valid as long
+ * as the policy is unmodified.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *iter will be NULL.
+ */
+ extern int qpol_validatetrans_get_expr_iter(const qpol_policy_t * policy, const qpol_validatetrans_t * vtrans,
+ qpol_iterator_t ** iter);
+
+/* expr_type values */
+#define QPOL_CEXPR_TYPE_NOT 1
+#define QPOL_CEXPR_TYPE_AND 2
+#define QPOL_CEXPR_TYPE_OR 3
+#define QPOL_CEXPR_TYPE_ATTR 4
+#define QPOL_CEXPR_TYPE_NAMES 5
+
+/**
+ * Get the code for the expression type of by an expression node.
+ * @patam policy The policy from which the expression comes.
+ * @param expr The expression node from which to get the expression type.
+ * @param expr_type Integer in which to store the expression type; the value
+ * will be one of QPOL_CEXPR_TYPE_* above.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *op will be 0.
+ */
+ extern int qpol_constraint_expr_node_get_expr_type(const qpol_policy_t * policy, const qpol_constraint_expr_node_t * expr,
+ uint32_t * expr_type);
+
+/* attr values */
+#define QPOL_CEXPR_SYM_USER 1
+#define QPOL_CEXPR_SYM_ROLE 2
+#define QPOL_CEXPR_SYM_TYPE 4
+#define QPOL_CEXPR_SYM_TARGET 8
+#define QPOL_CEXPR_SYM_XTARGET 16
+#define QPOL_CEXPR_SYM_L1L2 32
+#define QPOL_CEXPR_SYM_L1H2 64
+#define QPOL_CEXPR_SYM_H1L2 128
+#define QPOL_CEXPR_SYM_H1H2 256
+#define QPOL_CEXPR_SYM_L1H1 512
+#define QPOL_CEXPR_SYM_L2H2 1024
+
+/**
+ * Get the code for the symbol type used by an expression node.
+ * @param policy The policy from which the expression comes.
+ * @param expr The expression node from which to get the symbol type.
+ * Must be of expression type QPOL_CEXPR_TYPE_ATTR or QPOL_CEXPR_TYPE_NAMES.
+ * @param sym_type Integer in which to store the symbol type; the value
+ * will be a bitwise or'ed set of QPOL_CEXPR_SYM_* above.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *sym_type will be 0.
+ */
+ extern int qpol_constraint_expr_node_get_sym_type(const qpol_policy_t * policy, const qpol_constraint_expr_node_t * expr,
+ uint32_t * sym_type);
+
+/* op values */
+#define QPOL_CEXPR_OP_EQ 1
+#define QPOL_CEXPR_OP_NEQ 2
+#define QPOL_CEXPR_OP_DOM 3
+#define QPOL_CEXPR_OP_DOMBY 4
+#define QPOL_CEXPR_OP_INCOMP 5
+
+/**
+ * Get the operator used by an expression node.
+ * @param policy The policy from which the expression comes.
+ * @param expr The expression node from which to get the operator.
+ * Must be of expression type QPOL_CEXPR_TYPE_ATTR or QPOL_CEXPR_TYPE_NAMES.
+ * @param op Integer in which to store the operator; the value
+ * will be one of QPOL_CEXPR_OP_* above.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *op will be 0.
+ */
+ extern int qpol_constraint_expr_node_get_op(const qpol_policy_t * policy, const qpol_constraint_expr_node_t * expr,
+ uint32_t * op);
+
+/**
+ * Get an iterator of the names in an expression node.
+ * @param policy The policy from which the expression comes.
+ * @param expr The expression node from which to create the iterator.
+ * Must be of expression type QPOL_CEXPR_TYPE_NAMES.
+ * @param iter Iterator over items of type char* returned.
+ * The caller is responsible for calling qpol_iterator_destroy()
+ * to free memory used by this iterator. <b>The caller should call
+ * free() on the strings returned by qpol_iterator_get_item().</b>
+ * It is important to note that this iterator is only valid as long
+ * as the policy is unmodified.
+ * In the case where the symbol names are types, the name of a subtracted
+ * type will be prepended with a '-' character.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *iter will be NULL.
+ */
+ extern int qpol_constraint_expr_node_get_names_iter(const qpol_policy_t * policy, const qpol_constraint_expr_node_t * expr,
+ qpol_iterator_t ** iter);
+
+/**
+ * Get an iterator for the constraints on a class.
+ * @param policy The policy associated with the class.
+ * @param obj_class The class from which to create the iterator.
+ * @param constr Iterator over items of type qpol_constraint_t returned.
+ * The caller is responsible for calling qpol_iterator_destroy()
+ * to free memory used by this iterator. <b>The caller must also call free()
+ * on items returned by qpol_iterator_get_item() when using this iterator.</b>
+ * It is important to note that this iterator is only valid as long
+ * as the policy is unmodified.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *constr will be NULL.
+ */
+ extern int qpol_class_get_constraint_iter(const qpol_policy_t * policy, const qpol_class_t * obj_class,
+ qpol_iterator_t ** constr);
+
+/**
+ * Get an iterator for the validatetrans statements for a class.
+ * @param policy The policy associated with the class.
+ * @param obj_class The class from which to create the iterator.
+ * @param vtrans Iterator over items of type qpol_validatetrans_t returned.
+ * The caller is responsible for calling qpol_iterator_destroy()
+ * to free memory used by this iterator. <b>The caller must also call free()
+ * on items returned by qpol_iterator_get_item() when using this iterator.</b>
+ * It is important to note that this iterator is only valid as long
+ * as the policy is unmodified.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *vtrans will be NULL.
+ */
+ extern int qpol_class_get_validatetrans_iter(const qpol_policy_t * policy, const qpol_class_t * obj_class,
+ qpol_iterator_t ** vtrans);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* QPOL_CONSTRAINT_QUERY_H */
diff --git a/libqpol/include/qpol/context_query.h b/libqpol/include/qpol/context_query.h
new file mode 100644
index 0000000..d152d79
--- /dev/null
+++ b/libqpol/include/qpol/context_query.h
@@ -0,0 +1,93 @@
+/**
+ * @file
+ * Defines the public interface accessing contexts.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @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
+ */
+
+#ifndef QPOL_CONTEXT_QUERY_H
+#define QPOL_CONTEXT_QUERY_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stddef.h>
+#include <stdint.h>
+#include <qpol/policy.h>
+#include <qpol/user_query.h>
+#include <qpol/role_query.h>
+#include <qpol/type_query.h>
+#include <qpol/mls_query.h>
+
+ typedef struct qpol_context qpol_context_t;
+
+/**
+ * Get the datum for the user field of a context.
+ * @param policy The policy associated with the context.
+ * @param context The context from which to get the user.
+ * @param user Pointer in which to store the user datum.
+ * The caller should not free this pointer.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *user will be NULL.
+ */
+ extern int qpol_context_get_user(const qpol_policy_t * policy, const qpol_context_t * context, const qpol_user_t ** user);
+
+/**
+ * Get the datum for the role field of a context.
+ * @param policy The policy associated with the context.
+ * @param context The context from which to get the role.
+ * @param role Pointer in which to store the role datum.
+ * The caller should not free this pointer.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *role will be NULL.
+ */
+ extern int qpol_context_get_role(const qpol_policy_t * policy, const qpol_context_t * context, const qpol_role_t ** role);
+
+/**
+ * Get the datum for the type field of a context.
+ * @param policy The policy associated with the context.
+ * @param context The context from which to get the type.
+ * @param type Pointer in which to store the type datum.
+ * The caller should not free this pointer.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *type will be NULL.
+ */
+ extern int qpol_context_get_type(const qpol_policy_t * policy, const qpol_context_t * context, const qpol_type_t ** type);
+
+/**
+ * Get the datum for the MLS range field of a context.
+ * @param policy The policy associated with the context.
+ * @param context The context from which to get the MLS range.
+ * @param range Pointer in which to store the MLS range.
+ * The caller should not free this pointer.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *range will be NULL.
+ */
+ extern int qpol_context_get_range(const qpol_policy_t * policy, const qpol_context_t * context,
+ const qpol_mls_range_t ** range);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* QPOL_CONTEXT_QUERY_H */
diff --git a/libqpol/include/qpol/fs_use_query.h b/libqpol/include/qpol/fs_use_query.h
new file mode 100644
index 0000000..c45ae44
--- /dev/null
+++ b/libqpol/include/qpol/fs_use_query.h
@@ -0,0 +1,115 @@
+/**
+ * @file
+ * Defines the public interface for searching and iterating over fs_use statements.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @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
+ */
+
+#ifndef QPOL_FS_USE_QUERY_H
+#define QPOL_FS_USE_QUERY_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stddef.h>
+#include <stdint.h>
+#include <qpol/iterator.h>
+#include <qpol/policy.h>
+#include <qpol/context_query.h>
+
+ typedef struct qpol_fs_use qpol_fs_use_t;
+
+/**
+ * Get a fs_use statement by file system name.
+ * @param policy The policy from which to get the fs_use statement.
+ * @param name The name of the file system.
+ * @param ocon Pointer in which to store the fs_use statement.
+ * The caller should not free this pointer.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *ocon will be NULL.
+ */
+ extern int qpol_policy_get_fs_use_by_name(const qpol_policy_t * policy, const char *name, const qpol_fs_use_t ** ocon);
+
+/**
+ * Get an iterator for the fs_use statements in a policy.
+ * @param policy The policy from which to create the iterator.
+ * @param iter Iterator over items of type qpol_fs_use_t returned.
+ * The caller is responsible for calling qpol_iterator_destroy
+ * to free memory used by this iterator.
+ * It is important to note that this iterator is only valid as long
+ * as the policy is unmodified.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *iter will be NULL.
+ */
+ extern int qpol_policy_get_fs_use_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter);
+
+/**
+ * Get the file system name from a fs_use statement.
+ * @param policy The policy associated with the fs_use statement.
+ * @param ocon The fs_use statement from which to get the name.
+ * @param name Pointer to the string in which to store the name.
+ * The caller should not free this string.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *name will be NULL.
+ */
+ extern int qpol_fs_use_get_name(const qpol_policy_t * policy, const qpol_fs_use_t * ocon, const char **name);
+
+/* The defines QPOL_FS_USE_XATTR through QPOL_FS_USE_NONE are
+ * copied from sepol/policydb/services.h.
+ * QPOL_FS_USE_PSID is an extension to support v12 policies. */
+#define QPOL_FS_USE_XATTR 1U
+#define QPOL_FS_USE_TRANS 2U
+#define QPOL_FS_USE_TASK 3U
+#define QPOL_FS_USE_GENFS 4U
+#define QPOL_FS_USE_NONE 5U
+#define QPOL_FS_USE_PSID 6U
+
+/**
+ * Get the labeling behavior from a fs_use statement.
+ * @param policy The policy associated with the fs_use statement.
+ * @param ocon The fs_use statement from which to get the behavior.
+ * @param behavior Pointer to be set to the value of the labeling behavior.
+ * The value will be one of the QPOL_FS_USE_* values defined above.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *behavior will be 0.
+ */
+ extern int qpol_fs_use_get_behavior(const qpol_policy_t * policy, const qpol_fs_use_t * ocon, uint32_t * behavior);
+
+/**
+ * Get the context from a fs_use statement.
+ * @param policy The policy associated with the fs_use statement.
+ * @param ocon The fs_use statement from which to get the context.
+ * @param context Pointer in which to store the context.
+ * The caller should not free this pointer.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *context will be NULL. It is considered an
+ * error to call this function if behavior is QPOL_FS_USE_PSID.
+ */
+ extern int qpol_fs_use_get_context(const qpol_policy_t * policy, const qpol_fs_use_t * ocon,
+ const qpol_context_t ** context);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* QPOL_FS_USE_QUERY_H */
diff --git a/libqpol/include/qpol/genfscon_query.h b/libqpol/include/qpol/genfscon_query.h
new file mode 100644
index 0000000..f89795a
--- /dev/null
+++ b/libqpol/include/qpol/genfscon_query.h
@@ -0,0 +1,128 @@
+/**
+ * @file
+ * Defines the public interface for searching and iterating over genfscon statements.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 20062007 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
+ */
+
+#ifndef QPOL_OCON_QUERY_H
+#define QPOL_OCON_QUERY_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stddef.h>
+#include <stdint.h>
+#include <qpol/iterator.h>
+#include <qpol/policy.h>
+
+ typedef struct qpol_genfscon qpol_genfscon_t;
+
+/**
+ * Get a genfscon statement by file system name and path.
+ * @param policy The policy from which to get the genfscon statement.
+ * @param name The name of the file system.
+ * @param path The path relative to the filesystem mount point.
+ * @param genfscon Pointer in which to store the genfscon statement.
+ * The caller should call free() on this pointer.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *genfscon will be NULL.
+ */
+ extern int qpol_policy_get_genfscon_by_name(const qpol_policy_t * policy, const char *name, const char *path,
+ qpol_genfscon_t ** genfscon);
+
+/**
+ * Get an iterator for the genfscon statements in a policy.
+ * @param policy The policy from which to create the iterator.
+ * @param iter Iterator over items of type qpol_genfscon_t returned.
+ * The caller is responsible for calling qpol_iterator_destroy()
+ * to free memory used by this iterator. The caller must also call free()
+ * on items returned by qpol_iterator_get_item() when using this iterator.
+ * It is important to note that this iterator is only valid as long
+ * as the policy is unmodified.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *iter will be NULL.
+ */
+ extern int qpol_policy_get_genfscon_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter);
+
+/**
+ * Get the file system name from a gefscon statement.
+ * @param policy The policy associated with the genfscon statement.
+ * @param genfs The genfscon statement from which to get the name.
+ * @param name Pointer to th string in which to store the name.
+ * The caller should not free this string.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *name will be NULL.
+ */
+ extern int qpol_genfscon_get_name(const qpol_policy_t * policy, const qpol_genfscon_t * genfs, const char **name);
+
+/**
+ * Get the relative path from a gefscon statement.
+ * @param policy The policy associated with the genfscon statement.
+ * @param genfs The genfscon statement from which to get the path.
+ * @param path Pointer to the string in which to store the path.
+ * The caller should not free this string.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *path will be NULL.
+ */
+ extern int qpol_genfscon_get_path(const qpol_policy_t * policy, const qpol_genfscon_t * genfs, const char **path);
+
+/* values from flask do not change */
+#define QPOL_CLASS_ALL 0U
+#define QPOL_CLASS_BLK_FILE 11U
+#define QPOL_CLASS_CHR_FILE 10U
+#define QPOL_CLASS_DIR 7U
+#define QPOL_CLASS_FIFO_FILE 13U
+#define QPOL_CLASS_FILE 6U
+#define QPOL_CLASS_LNK_FILE 9U
+#define QPOL_CLASS_SOCK_FILE 12U
+
+/**
+ * Get the object class from a genfscon statement.
+ * @param policy The policy associated with the genfscon statement.
+ * @param genfs The genfscon statement from which to get the path.
+ * @param obj_class Pointer in which to store the integer code for the
+ * object class. See QPOL_CLASS_* defines above for values.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *class will be 0.
+ */
+ extern int qpol_genfscon_get_class(const qpol_policy_t * policy, const qpol_genfscon_t * genfs, uint32_t * obj_class);
+
+/**
+ * Get the context from a path component of a genfscon statement.
+ * @param policy The policy associated with the genfscon statement.
+ * @param genfscon The genfscon statement from which to get
+ * the context.
+ * @param context Pointer in which to store the context.
+ * The caller should not free this pointer.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *context will be NULL.
+ */
+ extern int qpol_genfscon_get_context(const qpol_policy_t * policy, const qpol_genfscon_t * genfscon,
+ const qpol_context_t ** context);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* QPOL_OCON_QUERY_H */
diff --git a/libqpol/include/qpol/isid_query.h b/libqpol/include/qpol/isid_query.h
new file mode 100644
index 0000000..56ff4d2
--- /dev/null
+++ b/libqpol/include/qpol/isid_query.h
@@ -0,0 +1,91 @@
+/**
+ * @file
+ * Defines the public interface for searching and iterating over initial SIDs.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @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
+ */
+
+#ifndef QPOL_ISID_QUERY_H
+#define QPOL_ISID_QUERY_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stddef.h>
+#include <stdint.h>
+#include <qpol/iterator.h>
+#include <qpol/policy.h>
+
+ typedef struct qpol_isid qpol_isid_t;
+
+/**
+ * Get an initial SID statement by name.
+ * @param policy The policy from which to get the initial SID statement.
+ * @param name The name of the initial SID.
+ * @param ocon Pointer in which to store the initial SID.
+ * The caller should not free this pointer.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *ocon will be NULL.
+ */
+ extern int qpol_policy_get_isid_by_name(const qpol_policy_t * policy, const char *name, const qpol_isid_t ** ocon);
+
+/**
+ * Get an iterator for the initial SID statements in a policy.
+ * @param policy The policy from which to create the iterator.
+ * @param iter Iterator over items of type qpol_isid_t returned.
+ * The caller is responsible for calling qpol_iterator_destroy
+ * to free memory used by this iterator.
+ * It is important to note that this iterator is only valid as long
+ * as the policy is unmodified.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *iter will be NULL.
+ */
+ extern int qpol_policy_get_isid_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter);
+
+/**
+ * Get the name from an initial SID statement.
+ * @param policy The policy associated with the initial SID.
+ * @param ocon The initial SID from which to get the name.
+ * @param name Pointer to the string in which to store the name.
+ * The caller should not free this string.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *name will be NULL.
+ */
+ extern int qpol_isid_get_name(const qpol_policy_t * policy, const qpol_isid_t * ocon, const char **name);
+
+/**
+ * Get the context from an initial SID statement.
+ * @param policy The policy associated with the inital SID.
+ * @param ocon The initial SID from which to get the context.
+ * @param context Pointer in which to store the context.
+ * The caller should not free this pointer.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *context will be NULL.
+ */
+ extern int qpol_isid_get_context(const qpol_policy_t * policy, const qpol_isid_t * ocon, const qpol_context_t ** context);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* QPOL_ISID_QUERY_H */
diff --git a/libqpol/include/qpol/iterator.h b/libqpol/include/qpol/iterator.h
new file mode 100644
index 0000000..e7bb8be
--- /dev/null
+++ b/libqpol/include/qpol/iterator.h
@@ -0,0 +1,95 @@
+/**
+ * @file
+ * Defines the public API for qpol_iterator; this structure
+ * is used when requesting lists of components from the policy
+ * database.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @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
+ */
+
+#ifndef QPOL_ITERATOR_H
+#define QPOL_ITERATOR_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stddef.h>
+
+ struct qpol_iterator;
+ typedef struct qpol_iterator qpol_iterator_t;
+
+/**
+ * Free memory used by the iterator.
+ * @param iter Pointer to the iterator to be freed; frees all
+ * memory used by the iterator and the iterator itself. On returning
+ * *iter will be NULL.
+ */
+ extern void qpol_iterator_destroy(qpol_iterator_t ** iter);
+
+/**
+ * Get the item at the current position of the iterator.
+ * @param iter The iterator from which to get the item.
+ * @param item Pointer in which to store the current item; the caller is
+ * responsible for safely casting this pointer. Unless specifically
+ * noted by the function creating the iterator, the item set
+ * by this function should not be freed. If the iterator is at
+ * the end (i.e. all items have been traversed) *item will be NULL.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *item will be NULL.
+ */
+ extern int qpol_iterator_get_item(const qpol_iterator_t * iter, void **item);
+
+/**
+ * Advance the iterator to the next item.
+ * @param iter The iterator to advance; internal state data will change.
+ * @return Returns 0 on success and < 0 on failure; advancing an
+ * iterator that is at the end fails (and returns < 0). If the call fails,
+ * errno will be set.
+ */
+ extern int qpol_iterator_next(qpol_iterator_t * iter);
+
+/**
+ * Determine if an iterator is at the end.
+ * @param iter The iterator to check.
+ * @return Returns non-zero if the current position of the iterator
+ * is at the end of the list (i.e. past the last valid item) and
+ * zero in any other case. If there is an error determining if
+ * the iterator is at the end then non-zero will be returned.
+ */
+ extern int qpol_iterator_end(const qpol_iterator_t * iter);
+
+/**
+ * Get the total number of items in the list traversed by the iterator.
+ * @param iter The iterator from which to get the number of items.
+ * @param size Pointer in which to store the number of items.
+ * Must be non-NULL.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *size will be 0.
+ */
+ extern int qpol_iterator_get_size(const qpol_iterator_t * iter, size_t * size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* QPOL_ITERATOR */
diff --git a/libqpol/include/qpol/mls_query.h b/libqpol/include/qpol/mls_query.h
new file mode 100644
index 0000000..c5fadc5
--- /dev/null
+++ b/libqpol/include/qpol/mls_query.h
@@ -0,0 +1,260 @@
+/**
+ * @file
+ * Defines the public interface for searching and iterating over
+ * policy MLS components.
+ *
+ * @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
+ */
+
+#ifndef QPOL_MLS_QUERY_H
+#define QPOL_MLS_QUERY_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stddef.h>
+#include <stdint.h>
+
+ typedef struct qpol_level qpol_level_t;
+ typedef struct qpol_cat qpol_cat_t;
+ typedef struct qpol_mls_range qpol_mls_range_t;
+ typedef struct qpol_mls_level qpol_mls_level_t;
+
+#include <qpol/iterator.h>
+#include <qpol/policy.h>
+
+/* level */
+/**
+ * Get datum for a security level by (sensitivity) name.
+ * @param policy The policy from which to get the level datum.
+ * @param name The sensitivity name; searching is case sensitive.
+ * @param datum Pointer in which to store the level datum. Must be non-NULL.
+ * The caller should not free this pointer.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *datum will be NULL.
+ */
+ extern int qpol_policy_get_level_by_name(const qpol_policy_t * policy, const char *name, const qpol_level_t ** datum);
+
+/**
+ * Get an iterator for the levels in a policy.
+ * @param policy The policy from which to create the iterator.
+ * @param iter Iterator of type qpol_level_t* returned;
+ * The caller is responsible for calling qpol_iterator_destroy
+ * to free memory used; it is important to note that the iterator
+ * is valid only as long as the policy is unchanged.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *iter will be NULL.
+ */
+ extern int qpol_policy_get_level_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter);
+
+/**
+ * Determine if a level is an alias for another level.
+ * @param policy The policy associated with the level datum.
+ * @param datum The level to check.
+ * @param isalias Pointer in which to store the alias state of
+ * the level. Must be non-NULL.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *isalias will be 0 (false).
+ */
+ extern int qpol_level_get_isalias(const qpol_policy_t * policy, const qpol_level_t * datum, unsigned char *isalias);
+
+/**
+ * Get the integer value associated with the sensitivity of a level.
+ * Values range from 1 to the number of declared levels in the policy.
+ * @param policy The policy associated with the level.
+ * @param datum The level datum from which to get the value.
+ * @param value Pointer to the integer to set to value. Must be non-NULL.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *value will be 0.
+ */
+ extern int qpol_level_get_value(const qpol_policy_t * policy, const qpol_level_t * datum, uint32_t * value);
+
+/**
+ * Get an iterator for the categories associated with a level.
+ * @param policy The policy associated with the level.
+ * @param datum The level from which to get the categories.
+ * @param cats Iterator of type qpol_cat_t* returned;
+ * the categories are in policy order. The caller is responsible
+ * for calling qpol_iterator_destroy to free memory used;
+ * it is important to note that the iterator is valid only as long
+ * as the policy is unchanged.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *cats will be NULL.
+ */
+ extern int qpol_level_get_cat_iter(const qpol_policy_t * policy, const qpol_level_t * datum, qpol_iterator_t ** cats);
+
+/**
+ * Get the name which identifies a level from its datum.
+ * @param policy The policy associated with the level.
+ * @param datum The level from which to get the name.
+ * @param name Pointer in which to store the name. Must be non-NULL;
+ * the caller should not free this string. If the sensitivity is an
+ * alias, the primary name will be returned.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *name will be NULL.
+ */
+ extern int qpol_level_get_name(const qpol_policy_t * policy, const qpol_level_t * datum, const char **name);
+
+/**
+ * Get an iterator for the list of aliases for a level.
+ * @param policy The policy associated with the level.
+ * @param datum The level for which to get aliases.
+ * @param aliases Iterator of type char* returned; the caller is
+ * responsible for calling qpol_iterator_destroy to free
+ * memory used; it is important to note that the iterator is valid
+ * only as long as the policy is unchanged. If a level has no aliases,
+ * the iterator will be at end and have size 0.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *aliases will be NULL.
+ */
+ extern int qpol_level_get_alias_iter(const qpol_policy_t * policy, const qpol_level_t * datum, qpol_iterator_t ** aliases);
+
+/* cat */
+/**
+ * Get the datum for a category by name.
+ * @param policy The policy from which to get the category.
+ * @param name The name of the category; searching is case sensitive.
+ * @param datum Pointer in which to store the datum; the caller should
+ * not free this pointer.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *datum will be NULL.
+ */
+ extern int qpol_policy_get_cat_by_name(const qpol_policy_t * policy, const char *name, const qpol_cat_t ** datum);
+
+/**
+ * Get an iterator for the categories declared in a policy.
+ * @param policy The policy from which to create the iterator.
+ * @param iter Iterator of type qpol_cat_t* returned;
+ * the categories are in policy order. The caller is responsible
+ * for calling qpol_iterator_destroy to free the memory used;
+ * it is important to note that the iterator is only valid as
+ * long as the policy is unchanged.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *iter will be NULL.
+ */
+ extern int qpol_policy_get_cat_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter);
+
+/**
+ * Get the integer value associated with a category. Values range
+ * from 1 to the number of categories declared in the policy.
+ * @param policy The policy associated with the category.
+ * @param datum The category for which to get the value.
+ * @param value Pointer to the integer to set to value. Must be non-NULL.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *value will be 0.
+ */
+ extern int qpol_cat_get_value(const qpol_policy_t * policy, const qpol_cat_t * datum, uint32_t * value);
+
+/**
+ * Determine if a category is an alias for another category.
+ * @param policy The policy associated with the category.
+ * @param datum The category to check.
+ * @param isalias Pointer in which to store the alias state of the
+ * category; must be non-NULL.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *isalias will be 0 (false).
+ */
+ extern int qpol_cat_get_isalias(const qpol_policy_t * policy, const qpol_cat_t * datum, unsigned char *isalias);
+
+/**
+ * Get the name which identifies a category from its datum.
+ * @param policy The policy associated with the category.
+ * @param datum The category from which to get the name.
+ * @param name Pointer in which to store the name. Must be non-NULL;
+ * the caller should not free the string. If the category is an alias
+ * the primary name will be returned.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *name will be NULL.
+ */
+ extern int qpol_cat_get_name(const qpol_policy_t * policy, const qpol_cat_t * datum, const char **name);
+
+/**
+ * Get an iterator for the list of aliases for a category.
+ * @param policy The policy associated with the category.
+ * @param datum The category for which to get aliases.
+ * @param aliases Iterator of type char* returned; the caller is
+ * responsible for calling qpol_iterator_destroy to free
+ * memory used; it is important to note that the iterator is valid
+ * only as long as the policy is unchanged. If a category has no aliases,
+ * the iterator will be at end and have size 0.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *aliases will be NULL.
+ */
+ extern int qpol_cat_get_alias_iter(const qpol_policy_t * policy, const qpol_cat_t * datum, qpol_iterator_t ** aliases);
+
+/* mls range */
+/**
+ * Get the low level from a MLS range.
+ * @param policy The policy associated with the MLS components of range.
+ * @param range The range from which to get the low level.
+ * @param level Pointer in which to store the level; the caller
+ * should not free this pointer.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *level will be NULL.
+ */
+ extern int qpol_mls_range_get_low_level(const qpol_policy_t * policy, const qpol_mls_range_t * range,
+ const qpol_mls_level_t ** level);
+
+/**
+ * Get the high level from a MLS range.
+ * @param policy The policy associated with the MLS components of range.
+ * @param range The range from which to get the high level.
+ * @param level Pointer in which to store the level; the caller
+ * should not free this pointer.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *level will be NULL.
+ */
+ extern int qpol_mls_range_get_high_level(const qpol_policy_t * policy, const qpol_mls_range_t * range,
+ const qpol_mls_level_t ** level);
+
+/* mls_level */
+/**
+ * Get the name of the sensitivity from a MLS level.
+ * @param policy The policy associated with the MLS components of level.
+ * @param level The level from which to get the sensitivity name.
+ * @param name Pointer in which to store the name; the caller
+ * should not free this string.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *name will be NULL.
+ */
+ extern int qpol_mls_level_get_sens_name(const qpol_policy_t * policy, const qpol_mls_level_t * level, const char **name);
+
+/**
+ * Get an iterator for the categories in a MLS level. The list will be
+ * in policy order.
+ * @param policy The policy associated with the MLS components of level.
+ * @param level The level from which to get the categories.
+ * @param cats Iterator of type qpol_cat_t* returned; the list is in
+ * policy order. The caller is responsible for calling
+ * qpol_iterator_destroy to free memory used; it is important to note
+ * that an iterator is only valid as long as the policy is unchanged.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *cats will be NULL.
+ */
+ extern int qpol_mls_level_get_cat_iter(const qpol_policy_t * policy, const qpol_mls_level_t * level,
+ qpol_iterator_t ** cats);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* QPOL_MLS_QUERY_H */
diff --git a/libqpol/include/qpol/mlsrule_query.h b/libqpol/include/qpol/mlsrule_query.h
new file mode 100644
index 0000000..5c4b832
--- /dev/null
+++ b/libqpol/include/qpol/mlsrule_query.h
@@ -0,0 +1,104 @@
+/**
+ * @file
+ * Defines the public interface for searching and iterating over
+ * range transition rules.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @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
+ */
+
+#ifndef QPOL_MLSRULE_QUERY_H
+#define QPOL_MLSRULE_QUERY_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <qpol/policy.h>
+
+ typedef struct qpol_range_trans qpol_range_trans_t;
+
+/**
+ * Get an iterator over all range transition rules in a policy.
+ * @param policy Policy from which to get the range transitions.
+ * @param iter Iterator over items of type qpol_range_trans_t returned.
+ * The caller is responsible for calling qpol_iterator_destroy()
+ * to free memory used by this iterator.
+ * It is important to note that this iterator is only valid as long as
+ * the policy is unmodifed.
+ * @returm 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *iter will be NULL.
+ */
+ extern int qpol_policy_get_range_trans_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter);
+
+/**
+ * Get the source type from a range transition rule.
+ * @param policy Policy from which the rule comes.
+ * @param rule The rule from which to get the source type.
+ * @param source Pointer in which to store the source type.
+ * The caller should not free this pointer.
+ * @returm 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *source will be NULL.
+ */
+ extern int qpol_range_trans_get_source_type(const qpol_policy_t * policy, const qpol_range_trans_t * rule,
+ const qpol_type_t ** source);
+
+/**
+ * Get the target type from a range transition rule.
+ * @param policy Policy from which the rule comes.
+ * @param rule The rule from which to get the target type.
+ * @param target Pointer in which to store the target type.
+ * The caller should not free this pointer.
+ * @returm 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *target will be NULL.
+ */
+ extern int qpol_range_trans_get_target_type(const qpol_policy_t * policy, const qpol_range_trans_t * rule,
+ const qpol_type_t ** target);
+
+/**
+ * Get the target class from a range transition rule.
+ * @param policy Policy from which the rule comes.
+ * @param rule The rule from which to get the target class.
+ * @param target Pointer in which to store the target class.
+ * The caller should not free this pointer.
+ * @returm 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *target will be NULL.
+ */
+ extern int qpol_range_trans_get_target_class(const qpol_policy_t * policy, const qpol_range_trans_t * rule,
+ const qpol_class_t ** target);
+
+/**
+ * Get the range from a range transition rule.
+ * @param policy Policy from which the rule comes.
+ * @param rule The rule from which to get the range.
+ * @param range Pointer in which to store the range.
+ * The caller should not free this pointer.
+ * @returm 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *range will be NULL.
+ */
+ extern int qpol_range_trans_get_range(const qpol_policy_t * policy, const qpol_range_trans_t * rule,
+ const qpol_mls_range_t ** range);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* QPOL_MLSRULE_QUERY_H */
diff --git a/libqpol/include/qpol/module.h b/libqpol/include/qpol/module.h
new file mode 100644
index 0000000..d684c40
--- /dev/null
+++ b/libqpol/include/qpol/module.h
@@ -0,0 +1,125 @@
+/**
+ * @file
+ * Defines the public interface the policy modules.
+ *
+ * @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
+ */
+
+#ifndef QPOL_MODULE_H
+#define QPOL_MODULE_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stdint.h>
+
+ typedef struct qpol_module qpol_module_t;
+
+#define QPOL_MODULE_UNKNOWN 0
+#define QPOL_MODULE_BASE 1
+#define QPOL_MODULE_OTHER 2
+
+/**
+ * Create a qpol module from a policy package file. Newly created
+ * modules are enabled by default.
+ * @param path The file from which to read the module. This string
+ * will be duplicated.
+ * @param module Pointer in which to store the newly allocated
+ * module. The caller is responsible for calling qpol_module_destroy()
+ * to free memory used by this module.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *module will be NULL.
+ */
+ extern int qpol_module_create_from_file(const char *path, qpol_module_t ** module);
+
+/**
+ * Free all memory used by a qpol module and set it to NULL. Does
+ * nothing if the pointer is already NULL.
+ * @param module Reference pointer to the module to destroy.
+ */
+ extern void qpol_module_destroy(qpol_module_t ** module);
+
+/**
+ * Get the path of the policy package file used to create this module.
+ * @param module The module from which to get the path.
+ * @param path Pointer to the string in which to store the path. <b>The
+ * caller should not free this string.</b>
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *path will be NULL.
+ */
+ extern int qpol_module_get_path(const qpol_module_t * module, const char **path);
+
+/**
+ * Get the name of a module.
+ * @param module The module from which to get the name.
+ * @param name Pointer to the string in which to store the name. <b>The
+ * caller should not free this string.</b> If the module is a base
+ * module the name will be NULL.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *name will be NULL.
+ */
+ extern int qpol_module_get_name(const qpol_module_t * module, const char **name);
+
+/**
+ * Get the version of a module.
+ * @param module The module from which to get the version.
+ * @param version Pointer to string in which to store the version. <b>The
+ * caller should not free this string.</b>
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *version will be NULL.
+ */
+ extern int qpol_module_get_version(const qpol_module_t * module, const char **version);
+
+/**
+ * Get the type of module (base or other).
+ * @param module The module from which to get the type.
+ * @param type Pointer to integer in which to store the type. Value
+ * will be one of QPOL_MODULE_BASE or QPOL_MODULE_OTHER.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *type will be QPOL_MODULE_UNKNOWN.
+ */
+ extern int qpol_module_get_type(const qpol_module_t * module, int *type);
+
+/**
+ * Determine if a module is enabled.
+ * @param module The module from which to get the enabled state.
+ * @param enabled Pointer to integer in which to store the state.
+ * Value will be 0 if module is disabled and non-zero if enabled.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *enabled will be 0.
+ */
+ extern int qpol_module_get_enabled(const qpol_module_t * module, int *enabled);
+
+/**
+ * Enable or disable a module. Note that the caller must still
+ * invoke qpol_policy_rebuild() to update the policy.
+ * @param module The module to enable or disable.
+ * @param enabled Non-zero to enable the module, zero to disable.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and the module will remain unchanged.
+ */
+ extern int qpol_module_set_enabled(qpol_module_t * module, int enabled);
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libqpol/include/qpol/netifcon_query.h b/libqpol/include/qpol/netifcon_query.h
new file mode 100644
index 0000000..b35c914
--- /dev/null
+++ b/libqpol/include/qpol/netifcon_query.h
@@ -0,0 +1,104 @@
+/**
+ * @file
+ * Defines the public interface for searching and iterating over netifcon statements.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @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
+ */
+
+#ifndef QPOL_NETIFCON_QUERY_H
+#define QPOL_NETIFCON_QUERY_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stddef.h>
+#include <stdint.h>
+#include <qpol/iterator.h>
+#include <qpol/policy.h>
+
+ typedef struct qpol_netifcon qpol_netifcon_t;
+
+/**
+ * Get a netifcon statement by interface name.
+ * @param policy The policy from which to get the netifcon statement.
+ * @param name The name of the interface.
+ * @param ocon Pointer in which to store the statement returned.
+ * The caller should not free this pointer.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *ocon will be NULL.
+ */
+ extern int qpol_policy_get_netifcon_by_name(const qpol_policy_t * policy, const char *name, const qpol_netifcon_t ** ocon);
+
+/**
+ * Get an iterator for the netifcon statements in a policy.
+ * @param policy The policy from which to create the iterator.
+ * @param iter Iterator over items of type qpol_netifcon_t returned.
+ * The caller is responsible for calling qpol_iterator_destroy
+ * to free memory used by this iterator.
+ * It is important to note that this iterator is only valid as long
+ * as the policy is unmodified.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *iter will be NULL.
+ */
+ extern int qpol_policy_get_netifcon_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter);
+
+/**
+ * Get the name of the interface from a netifcon statement.
+ * @param policy The policy associated wiht the netifcon statement.
+ * @param ocon The netifcon statement from which to get the name.
+ * @param name Pointer in which to store the interface name. The caller
+ * should not free this string.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *name will be NULL.
+ */
+ extern int qpol_netifcon_get_name(const qpol_policy_t * policy, const qpol_netifcon_t * ocon, const char **name);
+
+/**
+ * Get the message context from a netifcon statement.
+ * @param policy The policy associated with the netifcon statement.
+ * @param ocon The netifcon statement from which to get the message context.
+ * @parma context Pointer in which to store the context.
+ * The caller should not free this pointer.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *context will be NULL.
+ */
+ extern int qpol_netifcon_get_msg_con(const qpol_policy_t * policy, const qpol_netifcon_t * ocon,
+ const qpol_context_t ** context);
+
+/**
+ * Get the interface context from a netifcon statement.
+ * @param policy The policy associated with the netifcon statement.
+ * @param ocon The netifcon statement from which to get the interface context.
+ * @parma context Pointer in which to store the context.
+ * The caller should not free this pointer.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *context will be NULL.
+ */
+ extern int qpol_netifcon_get_if_con(const qpol_policy_t * policy, const qpol_netifcon_t * ocon,
+ const qpol_context_t ** context);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* QPOL_NETIFCON_QUERY_H */
diff --git a/libqpol/include/qpol/nodecon_query.h b/libqpol/include/qpol/nodecon_query.h
new file mode 100644
index 0000000..bd889f9
--- /dev/null
+++ b/libqpol/include/qpol/nodecon_query.h
@@ -0,0 +1,132 @@
+/**
+ * @file
+ * Defines the public interface for searching and iterating over nodecon statements.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @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
+ */
+
+#ifndef QPOL_NODECON_QUERY_H
+#define QPOL_NODECON_QUERY_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stddef.h>
+#include <stdint.h>
+#include <qpol/iterator.h>
+#include <qpol/policy.h>
+
+#define QPOL_IPV4 0
+#define QPOL_IPV6 1
+
+ typedef struct qpol_nodecon qpol_nodecon_t;
+
+/**
+ * Get a single nodecon statement by address, mask and protocol.
+ * @param policy The policy from which to get the nodecon statement.
+ * @param addr The IP address of the node, if IPv4 only addr[0] is used.
+ * @param mask The net mask of the node, if IPv4 only mask[0] is used.
+ * @param protocol The protocol used in the address and mask;
+ * set to QPOL_IPV4 for IPv4 and QPOL_IPV6 for IPv6.
+ * @param ocon Pointer in which to store the statement returned.
+ * The caller should call free() to free memory used by this pointer.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *ocon will be NULL.
+ */
+ extern int qpol_policy_get_nodecon_by_node(const qpol_policy_t * policy, uint32_t addr[4], uint32_t mask[4],
+ unsigned char protocol, qpol_nodecon_t ** ocon);
+
+/**
+ * Get an iterator for the nodecon statements in a policy.
+ * @param policy The policy from which to create the iterator.
+ * @param iter Iterator over items of type qpol_nodecon_t returned.
+ * The caller is responsible for calling qpol_iterator_destroy
+ * to free memory used by this iterator. The caller must also call free()
+ * on items returned by qpol_iterator_get_item() when using this iterator.
+ * It is important to note that this iterator is only valid as long
+ * as the policy is unmodified.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *iter will be NULL.
+ */
+ extern int qpol_policy_get_nodecon_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter);
+
+/**
+ * Get the IP address from a nodecon statement. Sets protocol to indicate
+ * the number of integers used by the array.
+ * @param policy The policy associated with the nodecon statement.
+ * @param ocon The nodecon statement from which to get the IP address.
+ * @param addr Pointer to the byte array of the IP addressto be set ;
+ * the caller should not free this pointer. The number of integers
+ * in this array is 1 if IPv4 and 4 if IPv6.
+ * @param protocol Pointer to be set to the protocol value; this
+ * will be set to QPOL_IPV4 for IPv4 and QPOL_IPV6 for IPv6.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set, addr will be NULL, and protocol will be 0.
+ */
+ extern int qpol_nodecon_get_addr(const qpol_policy_t * policy, const qpol_nodecon_t * ocon, uint32_t ** addr,
+ unsigned char *protocol);
+
+/**
+ * Get the net mask from a nodecon statement. Sets protocol to indicate
+ * the number of integers used by the array.
+ * @param policy The policy associated with the nodecon statement.
+ * @param ocon The nodecon statement from which to get the net mask.
+ * @param mask Pointer to the byte array of the net mask to be set;
+ * the caller should not free this pointer. The number of integers
+ * in this array is 1 if IPv4 and 4 if IPv6.
+ * @param protocol Pointer to be set to the protocol value; this
+ * will be set to QPOL_IPV4 for IPv4 and QPOL_IPV6 for IPv6.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set, mask will be NULL, and protocol will be 0.
+ */
+ extern int qpol_nodecon_get_mask(const qpol_policy_t * policy, const qpol_nodecon_t * ocon, uint32_t ** mask,
+ unsigned char *protocol);
+
+/**
+ * Get the protocol from a nodecon statement.
+ * @param policy The policy associated with the nodecon statement.
+ * @param ocon The nodecon statement from which to get the protocol.
+ * @param protocol Pointer to be set to the protocol value; this
+ * will be set to QPOL_IPV4 for IPv4 and QPOL_IPV6 for IPv6.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and protocol will be 0.
+ */
+ extern int qpol_nodecon_get_protocol(const qpol_policy_t * policy, const qpol_nodecon_t * ocon, unsigned char *protocol);
+
+/**
+ * Get the context from a nodecon statement.
+ * @param policy The policy associated with the nodecon statement.
+ * @param ocon The nodecon statement from which to get the context.
+ * @param context Pointer in which to store the context.
+ * The caller should not free this pointer.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *context will be NULL.
+ */
+ extern int qpol_nodecon_get_context(const qpol_policy_t * policy, const qpol_nodecon_t * ocon,
+ const qpol_context_t ** context);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* QPOL_NODECON_QUERY_H */
diff --git a/libqpol/include/qpol/permissive_query.h b/libqpol/include/qpol/permissive_query.h
new file mode 100644
index 0000000..e49d508
--- /dev/null
+++ b/libqpol/include/qpol/permissive_query.h
@@ -0,0 +1,68 @@
+/**
+ * @file
+ * Defines the public interface for searching and iterating over the permissive types.
+ *
+ * @author Steve Lawrence slawrence@tresys.com
+ *
+ * Copyright (C) 2006-2009 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
+ */
+
+#ifndef QPOL_PERMISSIVE_QUERY_H
+#define QPOL_PERMISSIVE_QUERY_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stddef.h>
+#include <stdint.h>
+#include <qpol/iterator.h>
+#include <qpol/policy.h>
+
+ typedef struct qpol_permissive qpol_permissive_t;
+
+/**
+ * Get an iterator for the permissive types in a policy.
+ * @param policy The policy from which to create the iterator.
+ * @param iter Iterator over items of type qpol_isid_t returned.
+ * The caller is responsible for calling qpol_iterator_destroy
+ * to free memory used by this iterator.
+ * It is important to note that this iterator is only valid as long
+ * as the policy is unmodified.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *iter will be NULL.
+ */
+ extern int qpol_policy_get_permissive_iter(const qpol_policy_t *policy, qpol_iterator_t **iter);
+
+
+/**
+ * Get the name which identifies a permissive type from its datum.
+ * @param policy The policy with which the permissive type is associated.
+ * @param datum Permissive datum for which to get the name. Must be non-NULL.
+ * @param name Pointer to the string in which to store the name.
+ * Must be non-NULL. The caller should not free the string.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *name will be NULL.
+ */
+ extern int qpol_permissive_get_name(const qpol_policy_t *policy, const qpol_permissive_t *datum, const char **name);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* QPOL_PERMISSIVE_QUERY_H */
diff --git a/libqpol/include/qpol/polcap_query.h b/libqpol/include/qpol/polcap_query.h
new file mode 100644
index 0000000..d8de4a0
--- /dev/null
+++ b/libqpol/include/qpol/polcap_query.h
@@ -0,0 +1,68 @@
+/**
+ * @file
+ * Defines the public interface for searching and iterating over the policy capabilities
+ *
+ * @author Steve Lawrence slawrence@tresys.com
+ *
+ * Copyright (C) 2006-2009 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
+ */
+
+#ifndef QPOL_POLCAP_QUERY_H
+#define QPOL_POLCAP_QUERY_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stddef.h>
+#include <stdint.h>
+#include <qpol/iterator.h>
+#include <qpol/policy.h>
+
+ typedef struct qpol_polcap qpol_polcap_t;
+
+/**
+ * Get an iterator for the policay capabilities in a policy.
+ * @param policy The policy from which to create the iterator.
+ * @param iter Iterator over items of type qpol_isid_t returned.
+ * The caller is responsible for calling qpol_iterator_destroy
+ * to free memory used by this iterator.
+ * It is important to note that this iterator is only valid as long
+ * as the policy is unmodified.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *iter will be NULL.
+ */
+ extern int qpol_policy_get_polcap_iter(const qpol_policy_t *policy, qpol_iterator_t **iter);
+
+
+/**
+ * Get the name which identifies a policy capability from its datum.
+ * @param policy The policy with which the policy capability is associated.
+ * @param datum Polcap datum for which to get the name. Must be non-NULL.
+ * @param name Pointer to the string in which to store the name.
+ * Must be non-NULL. The caller should not free the string.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *name will be NULL.
+ */
+ extern int qpol_polcap_get_name(const qpol_policy_t *policy, const qpol_polcap_t *datum, const char **name);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* QPOL_POLCAP_QUERY_H */
diff --git a/libqpol/include/qpol/policy.h b/libqpol/include/qpol/policy.h
new file mode 100644
index 0000000..ae4ea08
--- /dev/null
+++ b/libqpol/include/qpol/policy.h
@@ -0,0 +1,261 @@
+/**
+ * @file
+ * Defines the public interface the QPol policy.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author Brandon Whalen bwhalen@tresys.com
+ *
+ * Copyright (C) 2006-2008 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
+ */
+
+#ifndef QPOL_POLICY_H
+#define QPOL_POLICY_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stdarg.h>
+#include <stdint.h>
+
+ typedef struct qpol_policy qpol_policy_t;
+
+#include <qpol/avrule_query.h>
+#include <qpol/bool_query.h>
+#include <qpol/class_perm_query.h>
+#include <qpol/cond_query.h>
+#include <qpol/constraint_query.h>
+#include <qpol/context_query.h>
+#include <qpol/fs_use_query.h>
+#include <qpol/isid_query.h>
+#include <qpol/iterator.h>
+#include <qpol/genfscon_query.h>
+#include <qpol/mls_query.h>
+#include <qpol/mlsrule_query.h>
+#include <qpol/module.h>
+#include <qpol/netifcon_query.h>
+#include <qpol/nodecon_query.h>
+#include <qpol/permissive_query.h>
+#include <qpol/polcap_query.h>
+#include <qpol/portcon_query.h>
+#include <qpol/rbacrule_query.h>
+#include <qpol/role_query.h>
+#include <qpol/syn_rule_query.h>
+#include <qpol/terule_query.h>
+#include <qpol/type_query.h>
+#include <qpol/user_query.h>
+
+ typedef void (*qpol_callback_fn_t) (void *varg, const struct qpol_policy * policy, int level, const char *fmt,
+ va_list va_args);
+
+#define QPOL_POLICY_UNKNOWN -1
+#define QPOL_POLICY_KERNEL_SOURCE 0
+#define QPOL_POLICY_KERNEL_BINARY 1
+#define QPOL_POLICY_MODULE_BINARY 2
+
+/**
+ * When loading the policy, do not load neverallow rules.
+ */
+#define QPOL_POLICY_OPTION_NO_NEVERALLOWS 0x00000001
+
+/**
+ * When loading the policy, do not load any rules;
+ * this option implies QPOL_POLICY_OPTION_NO_NEVERALLOWS.
+ */
+#define QPOL_POLICY_OPTION_NO_RULES 0x00000002
+
+/**
+ * When loading the policy, attempt to interpret it as the way the
+ * running system would. If the policy is of a version higher than
+ * one supported by the system, then the policy will be downgraded to
+ * the system's maximum value.
+ */
+#define QPOL_POLICY_OPTION_MATCH_SYSTEM 0x00000004
+
+/**
+ * List of capabilities a policy may have. This list represents
+ * features of policy that may differ from version to version or
+ * based upon the format of the policy file. Note that "polcaps" in
+ * this case refers to "policy capabilities" that were introduced
+ * with version 22 policies.
+ */
+ typedef enum qpol_capability
+ {
+ /** The policy format stores the names of attributes. */
+ QPOL_CAP_ATTRIB_NAMES,
+ /** The policy format stores the syntactic rule type sets. */
+ QPOL_CAP_SYN_RULES,
+ /** The policy format stores rule line numbers (implies QPOL_CAP_SYN_RULES). */
+ QPOL_CAP_LINE_NUMBERS,
+ /** The policy version supports booleans and conditional statements. */
+ QPOL_CAP_CONDITIONALS,
+ /** The policy version supports MLS components and statements. */
+ QPOL_CAP_MLS,
+ /** The policy version has policy capabilities (polcaps). */
+ QPOL_CAP_POLCAPS,
+ /** The policy format supports linking loadable modules. */
+ QPOL_CAP_MODULES,
+ /** The policy was loaded with av/te rules. */
+ QPOL_CAP_RULES_LOADED,
+ /** The policy source may be displayed. */
+ QPOL_CAP_SOURCE,
+ /** The policy supports and was loaded with neverallow rules. */
+ QPOL_CAP_NEVERALLOW
+ } qpol_capability_e;
+
+/**
+ * Open a policy from a passed in file path.
+ * @param filename The name of the file to open.
+ * @param policy The policy to populate. The caller should not free
+ * this pointer.
+ * @param fn (Optional) If non-NULL, the callback to be used by the handle.
+ * @param varg (Optional) The argument needed by the handle callback.
+ * @param options Options to control loading only portions of a policy;
+ * must be a bitwise-or'd set of QPOL_POLICY_OPTION_* from above.
+ * @return Returns one of QPOL_POLICY_KERNEL_SOURCE,
+ * QPOL_POLICY_KERNEL_BINARY, or QPOL_POLICY_MODULE_BINARY on success
+ * and < 0 on failure; if the call fails, errno will be set and
+ * *policy will be NULL.
+ */
+ extern int qpol_policy_open_from_file(const char *filename, qpol_policy_t ** policy, qpol_callback_fn_t fn, void *varg,
+ const int options);
+
+/**
+ * Open a policy from a passed in file path but do not load any rules.
+ * @param filename The name of the file to open.
+ * @param policy The policy to populate. The caller should not free
+ * this pointer.
+ * @param fn (Optional) If non-NULL, the callback to be used by the handle.
+ * @param varg (Optional) The argument needed by the handle callback.
+ * @return Returns one of QPOL_POLICY_* above on success and < 0 on failure;
+ * if the call fails, errno will be set and *policy will be NULL.
+ * @deprecated use qpol_policy_open_from_file() with the option QPOL_POLICY_OPTION_NO_RULES instead.
+ */
+ extern int qpol_policy_open_from_file_no_rules(const char *filename, qpol_policy_t ** policy, qpol_callback_fn_t fn,
+ void *varg) __attribute__ ((deprecated));
+
+/**
+ * Open a policy from a passed in buffer.
+ * @param policy The policy to populate. The caller should not free
+ * this pointer.
+ * @param filedata The policy file stored in memory .
+ * @param size The size of filedata
+ * @param fn (Optional) If non-NULL, the callback to be used by the handle.
+ * @param varg (Optional) The argument needed by the handle callback.
+ * @param options Options to control loading only portions of a policy;
+ * must be a bitwise-or'd set of QPOL_POLICY_OPTION_* from above.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *policy will be NULL.
+ */
+ extern int qpol_policy_open_from_memory(qpol_policy_t ** policy, const char *filedata, size_t size, qpol_callback_fn_t fn,
+ void *varg, const int options);
+
+/**
+ * Close a policy and deallocate its memory. Does nothing if it is
+ * already NULL.
+ * @param policy Reference to the policy to close. The pointer will
+ * be set to NULL afterwards.
+ */
+ extern void qpol_policy_destroy(qpol_policy_t ** policy);
+
+/**
+ * Re-evaluate all conditionals in the policy updating the state
+ * and setting the appropriate rule list as emabled for each.
+ * This call modifies the policy.
+ * @param policy The policy for which to re-evaluate the conditionals.
+ * This policy will be modified by this function.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set. On failure, the policy state may be inconsistent.
+ */
+ extern int qpol_policy_reevaluate_conds(qpol_policy_t * policy);
+
+/**
+ * Append a module to a policy. The policy now owns the module.
+ * Note that the caller must still invoke qpol_policy_rebuild()
+ * to update the policy.
+ * @param policy The policy to which to add the module.
+ * @param module The module to append. <b>The caller should not
+ * destroy this module if this function succeeds.</b>
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and both the policy and the module will
+ * remain unchanged. If the call fails, the caller is still
+ * responsible for calling qpol_module_destroy().
+ */
+ extern int qpol_policy_append_module(qpol_policy_t * policy, qpol_module_t * module);
+
+/**
+ * Rebuild the policy. If the options provided are the same as those
+ * provied to the last call to rebuild or open and the modules were not
+ * changed, this function does nothing; otherwise, re-link all enabled
+ * modules with the base and then call expand. If the syntactic rule
+ * table was previously built, the caller should call
+ * qpol_policy_build_syn_rule_table() after calling this function.
+ * @param policy The policy to rebuild.
+ * This policy will be altered by this function.
+ * @param options Options to control loading only portions of a policy;
+ * must be a bitwise-or'd set of QPOL_POLICY_OPTION_* from above.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and the policy will be reverted to its previous state.
+ */
+ extern int qpol_policy_rebuild(qpol_policy_t * policy, const int options);
+
+/**
+ * Get an iterator of all modules in a policy.
+ * @param policy The policy from which to get the iterator.
+ * @param iter Iteraror of modules (of type qpol_module_t) returned.
+ * The caller should not destroy the modules returned by
+ * qpol_iterator_get_item().
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *iter will be NULL.
+ */
+ extern int qpol_policy_get_module_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter);
+
+/**
+ * Get the version number of the policy.
+ * @param policy The policy for which to get the version.
+ * @param version Pointer to the integer to set to the version number.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *version will be 0.
+ */
+ extern int qpol_policy_get_policy_version(const qpol_policy_t * policy, unsigned int *version);
+
+/**
+ * Get the type of policy (source, binary, or module).
+ * @param policy The policy from which to get the type.
+ * @param type Pointer to the integer in which to store the type.
+ * Value will be one of QPOL_POLICY_* from above.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *type will be QPOL_POLICY_UNKNOWN.
+ */
+ extern int qpol_policy_get_type(const qpol_policy_t * policy, int *type);
+
+/**
+ * Determine if a policy has support for a specific capability.
+ * @param policy The policy to check.
+ * @param cap The capability for which to check. Must be one of QPOL_CAP_*
+ * defined above.
+ * @return Non-zero if the policy has the specified capability, and zero otherwise.
+ */
+ extern int qpol_policy_has_capability(const qpol_policy_t * policy, qpol_capability_e cap);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libqpol/include/qpol/policy_extend.h b/libqpol/include/qpol/policy_extend.h
new file mode 100644
index 0000000..1a06a93
--- /dev/null
+++ b/libqpol/include/qpol/policy_extend.h
@@ -0,0 +1,86 @@
+/**
+ * @file
+ * Public interface for loading and using an extended
+ * policy image.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @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
+ */
+
+#ifndef QPOL_POLICY_EXTEND_H
+#define QPOL_POLICY_EXTEND_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <qpol/policy.h>
+#include <qpol/iterator.h>
+
+/**
+ * Build the table of syntactic rules for a policy.
+ * Subsequent calls to this function have no effect.
+ * @param policy The policy for which to build the table.
+ * This policy will be modified by this call.
+ * @return 0 on success and < 0 on error; if the call fails,
+ * errno will be set.
+ */
+ extern int qpol_policy_build_syn_rule_table(qpol_policy_t * policy);
+
+/* forward declarations: see avrule_query.h and terule_query.h */
+ struct qpol_avrule;
+ struct qpol_terule;
+
+/**
+ * Get an iterator over the syntactic rules contributing to an av rule.
+ * @param policy Policy associated with the rule.
+ * @param rule Rule from which to get the syntactic rules.
+ * @param iter Iterator over items of type qpol_syn_avrule_t returned.
+ * The caller is responsible for calling qpol_iterator_destroy()
+ * to free memory used by this iterator.
+ * It is important to note that this iterator is only valid as long as
+ * the policy is unmodified.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *iter will be NULL.
+ */
+ extern int qpol_avrule_get_syn_avrule_iter(const qpol_policy_t * policy, const struct qpol_avrule *rule,
+ qpol_iterator_t ** iter);
+
+/**
+ * Get an iterator over the syntactic rules contributing to a type rule.
+ * @param policy Policy associated with the rule.
+ * @param rule Rule from which to get the syntactic rules.
+ * @param iter Iterator over items of type qpol_syn_terule_t returned.
+ * The caller is responsible for calling qpol_iterator_destroy()
+ * to free memory used by this iterator.
+ * It is important to note that this iterator is only valid as long as
+ * the policy is unmodified.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *iter will be NULL.
+ */
+ extern int qpol_terule_get_syn_terule_iter(const qpol_policy_t * policy, const struct qpol_terule *rule,
+ qpol_iterator_t ** iter);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* QPOL_POLICY_EXTEND_H */
diff --git a/libqpol/include/qpol/portcon_query.h b/libqpol/include/qpol/portcon_query.h
new file mode 100644
index 0000000..63210fe
--- /dev/null
+++ b/libqpol/include/qpol/portcon_query.h
@@ -0,0 +1,118 @@
+/**
+ * @file
+ * Defines the public interface for searching and iterating over portcon statements.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @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
+ */
+
+#ifndef QPOL_PORTCON_QUERY_H
+#define QPOL_PORTCON_QUERY_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stddef.h>
+#include <stdint.h>
+#include <netinet/in.h>
+#include <qpol/iterator.h>
+#include <qpol/policy.h>
+
+ typedef struct qpol_portcon qpol_portcon_t;
+
+/**
+ * Get a single portcon statement by port range and protocol.
+ * @param policy The policy from which to get the portcon statement.
+ * @param low The low port of the range of ports (or single port).
+ * @param high The high port of the range of ports; if searching for a
+ * single port, set high equal to low.
+ * @param protocol The protocol used in the portcon statement.
+ * Value should be one of IPPROTO_TCP or IPPROTO_UDP from netinet/in.h
+ * @param ocon Pointer in which to store the statement returned.
+ * The caller should not free this pointer.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *ocon will be NULL.
+ */
+ extern int qpol_policy_get_portcon_by_port(const qpol_policy_t * policy, uint16_t low, uint16_t high, uint8_t protocol,
+ const qpol_portcon_t ** ocon);
+
+/**
+ * Get an iterator for the portcon statements in a policy.
+ * @param policy The policy from which to create the iterator.
+ * @param iter Iterator over items of type qpol_portcon_t returned.
+ * The caller is responsible for calling qpol_iterator_destroy
+ * to free memory used by this iterator.
+ * It is important to note that this iterator is only valid as long
+ * as the policy is unmodified.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *iter will be NULL.
+ */
+ extern int qpol_policy_get_portcon_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter);
+
+/**
+ * Get the protocol from a portcon statement.
+ * @param policy The policy associated with the portcon statement.
+ * @param ocon The portcon statement from which to get the protocol.
+ * @param protocol Pointer to set to the value of protocol.
+ * Value will be one of IPPROTO_TCP or IPPROTO_UDP from netinet/in.h
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *protocol will be 0;
+ */
+ extern int qpol_portcon_get_protocol(const qpol_policy_t * policy, const qpol_portcon_t * ocon, uint8_t * protocol);
+
+/**
+ * Get the low port from a portcon statement.
+ * @param policy the policy associated with the portcon statement.
+ * @param ocon The portcon statement from which to get the low port.
+ * @param port Pointer to set to the port number.
+ * @return 0 on success < 0 on failure; if the call fails,
+ * errno will be set and *port will be 0.
+ */
+ extern int qpol_portcon_get_low_port(const qpol_policy_t * policy, const qpol_portcon_t * ocon, uint16_t * port);
+
+/**
+ * Get the high port from a portcon statement.
+ * @param policy the policy associated with the portcon statement.
+ * @param ocon The portcon statement from which to get the high port.
+ * @param port Pointer to set to the port number.
+ * @return 0 on success < 0 on failure; if the call fails,
+ * errno will be set and *port will be 0.
+ */
+ extern int qpol_portcon_get_high_port(const qpol_policy_t * policy, const qpol_portcon_t * ocon, uint16_t * port);
+
+/**
+ * Get the context from a portcon statement.
+ * @param policy the policy associated with the portcon statement.
+ * @param ocon The portcon statement from which to get the context.
+ * @param context Pointer in which to store the context.
+ * The caller should not free this pointer.
+ * @return 0 on success < 0 on failure; if the call fails,
+ * errno will be set and *context will be NULL.
+ */
+ extern int qpol_portcon_get_context(const qpol_policy_t * policy, const qpol_portcon_t * ocon,
+ const qpol_context_t ** context);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* QPOL_PORTCON_QUERY_H */
diff --git a/libqpol/include/qpol/rbacrule_query.h b/libqpol/include/qpol/rbacrule_query.h
new file mode 100644
index 0000000..342e597
--- /dev/null
+++ b/libqpol/include/qpol/rbacrule_query.h
@@ -0,0 +1,130 @@
+/**
+ * @file
+ * Defines public interface for iterating over RBAC rules.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @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
+ */
+
+#ifndef QPOL_RBACRULE_QUERY
+#define QPOL_RBACRULE_QUERY
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <qpol/policy.h>
+#include <qpol/iterator.h>
+
+ typedef struct qpol_role_allow qpol_role_allow_t;
+ typedef struct qpol_role_trans qpol_role_trans_t;
+
+/**
+ * Get an iterator over all role allow rules in the policy.
+ * @param policy Policy from which to create the iterator.
+ * @param iter Iterator over items of type qpol_role_allow_t returned.
+ * The caller is responsible for calling qpol_iterator_destroy()
+ * to free memory used by this iterator.
+ * It is important to note that this iterator is only valid as long as
+ * the policy is unmodifed.
+ * @returm 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *iter will be NULL.
+ */
+ extern int qpol_policy_get_role_allow_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter);
+
+/**
+ * Get the source role from a role allow rule.
+ * @param policy The policy from which the rule comes.
+ * @param rule The rule from which to get the source role.
+ * @param source Pointer in which to store the source role.
+ * The caller should not free this pointer.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *source will be NULL.
+ */
+ extern int qpol_role_allow_get_source_role(const qpol_policy_t * policy, const qpol_role_allow_t * rule,
+ const qpol_role_t ** source);
+
+/**
+ * Get the target role from a role allow rule.
+ * @param policy The policy from which the rule comes.
+ * @param rule The rule from which to get the target role.
+ * @param target Pointer in which to store the target role.
+ * The caller should not free this pointer.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *target will be NULL.
+ */
+ extern int qpol_role_allow_get_target_role(const qpol_policy_t * policy, const qpol_role_allow_t * rule,
+ const qpol_role_t ** target);
+
+/**
+ * Get an iterator over all role transition rules in the policy.
+ * @param policy Policy from which to create the iterator.
+ * @param iter Iterator over items of type qpol_role_trans_t returned.
+ * The caller is responsible for calling qpol_iterator_destroy()
+ * to free memory used by this iterator.
+ * It is important to note that this iterator is only valid as long as
+ * the policy is unmodifed.
+ * @returm 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *iter will be NULL.
+ */
+ extern int qpol_policy_get_role_trans_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter);
+
+/**
+ * Get the source role from a role transition rule.
+ * @param policy The policy from which the rule comes.
+ * @param rule The rule from which to get the source role.
+ * @param source Pointer in which to store the source role.
+ * The caller should not free this pointer.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *source will be NULL.
+ */
+ extern int qpol_role_trans_get_source_role(const qpol_policy_t * policy, const qpol_role_trans_t * rule,
+ const qpol_role_t ** source);
+
+/**
+ * Get the target type from a role transition rule.
+ * @param policy The policy from which the rule comes.
+ * @param rule The rule from which to get the target type.
+ * @param target Pointer in which to store the target type.
+ * The caller should not free this pointer.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *target will be NULL.
+ */
+ extern int qpol_role_trans_get_target_type(const qpol_policy_t * policy, const qpol_role_trans_t * rule,
+ const qpol_type_t ** target);
+
+/**
+ * Get the default role from a role transition rule.
+ * @param policy The policy from which the rule comes.
+ * @param rule The rule from which to get the default role.
+ * @param dflt Pointer in which to store the default role.
+ * The caller should not free this pointer.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *dflt will be NULL.
+ */
+ extern int qpol_role_trans_get_default_role(const qpol_policy_t * policy, const qpol_role_trans_t * rule,
+ const qpol_role_t ** dflt);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* QPOL_RBACRULE_QUERY */
diff --git a/libqpol/include/qpol/role_query.h b/libqpol/include/qpol/role_query.h
new file mode 100644
index 0000000..c5739ab
--- /dev/null
+++ b/libqpol/include/qpol/role_query.h
@@ -0,0 +1,119 @@
+ /**
+ * @file
+ * Defines the public interface for searching and iterating over roles.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @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
+ */
+
+#ifndef QPOL_ROLE_QUERY_H
+#define QPOL_ROLE_QUERY_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stddef.h>
+#include <stdint.h>
+#include <qpol/iterator.h>
+#include <qpol/policy.h>
+
+ typedef struct qpol_role qpol_role_t;
+
+/**
+ * Get the datum for a role by name.
+ * @param policy The policy from which to get the role.
+ * @param name The name of the role; searching is case sensitive.
+ * @param datum Pointer in which to store the role datum; the caller
+ * should not free this pointer.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *datum will be NULL.
+ */
+ extern int qpol_policy_get_role_by_name(const qpol_policy_t * policy, const char *name, const qpol_role_t ** datum);
+
+/**
+ * Get an iterator for roles declared in the policy.
+ * @param policy The policy with which to create the iterator.
+ * @param iter Iterator of type qpol_role_t* returned;
+ * the caller is responsible for calling qpol_iterator_destroy to
+ * free memory used; it is important to note that the iterator
+ * is valid only as long as the policy is unchanged.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *iter will be NULL.
+ */
+ extern int qpol_policy_get_role_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter);
+
+/**
+ * Get the integer value associated with a role; values range from
+ * 1 to the number of declared roles.
+ * @param policy The policy associated with the role.
+ * @param datum The role from which to get the value.
+ * @param value Pointer to the integer to set to value. Must be non-NULL.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and value will be 0.
+ */
+ extern int qpol_role_get_value(const qpol_policy_t * policy, const qpol_role_t * datum, uint32_t * value);
+
+/**
+ * Get an iterator for the set of roles dominated by a role.
+ * @param policy The policy associated with the role.
+ * @param datum The role from which to get the dominated roles.
+ * @param dominates Iterator of type qpol_role_t* returned;
+ * the caller is responsible for calling qpol_iterator_destroy to
+ * free memory used; it is important to note that the iterator is
+ * valid only as long as the policy is unchanged. Note: By
+ * convention a role always dominates itself, so the user of this
+ * iterator should always check for this case.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *dominates will be NULL.
+ */
+ extern int qpol_role_get_dominate_iter(const qpol_policy_t * policy, const qpol_role_t * datum,
+ qpol_iterator_t ** dominates);
+
+/**
+ * Get an iterator for the set of types assigned to a role.
+ * @param policy The policy associated with the role.
+ * @param datum The role from which to get the types.
+ * @param types Iterator of type qpol_type_t* returned;
+ * the caller is responsible for calling qpol_iterator_destroy to
+ * free memory used; it is important to note that the iterator
+ * is valid only as long as the policy is unchanged.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and types will be NULL.
+ */
+ extern int qpol_role_get_type_iter(const qpol_policy_t * policy, const qpol_role_t * datum, qpol_iterator_t ** types);
+
+/**
+ * Get the name by which a role is identified from its datum.
+ * @param policy The policy associated with the role.
+ * @param datum The role for which to get the name.
+ * @param name Pointer in which to store the name; the caller
+ * should not free this string.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *name will be NULL.
+ */
+ extern int qpol_role_get_name(const qpol_policy_t * policy, const qpol_role_t * datum, const char **name);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* QPOL_ROLE_QUERY_H */
diff --git a/libqpol/include/qpol/syn_rule_query.h b/libqpol/include/qpol/syn_rule_query.h
new file mode 100644
index 0000000..446efbb
--- /dev/null
+++ b/libqpol/include/qpol/syn_rule_query.h
@@ -0,0 +1,314 @@
+/**
+ * @file
+ * Public interface for querying syntactic rules from the extended
+ * policy image.
+ *
+ * @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
+ */
+
+#ifndef QPOL_SYN_RULE_QUERY_H
+#define QPOL_SYN_RULE_QUERY_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <qpol/policy.h>
+#include <qpol/cond_query.h>
+#include <qpol/iterator.h>
+#include <stdint.h>
+
+ typedef struct qpol_type_set qpol_type_set_t;
+ typedef struct qpol_syn_avrule qpol_syn_avrule_t;
+ typedef struct qpol_syn_terule qpol_syn_terule_t;
+
+/**
+ * Get an iterator of the included types in a type set.
+ * @param policy Policy associated with the type set.
+ * @param ts Type set from which to get the included types.
+ * @param iter Iterator over items of type qpol_type_t returned.
+ * The caller is responsible for calling qpol_iterator_destroy()
+ * to free memory used by this iterator.
+ * It is important to note that this iterator is only valid as long as
+ * the policy is unmodifed.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *iter will be NULL.
+ */
+ extern int qpol_type_set_get_included_types_iter(const qpol_policy_t * policy, const qpol_type_set_t * ts,
+ qpol_iterator_t ** iter);
+
+/**
+ * Get an iterator of the subtracted types in a type set.
+ * @param policy Policy associated with the type set.
+ * @param ts Type set from which to get the subtracted types.
+ * @param iter Iterator over items of type qpol_type_t returned.
+ * The caller is responsible for calling qpol_iterator_destroy()
+ * to free memory used by this iterator.
+ * It is important to note that this iterator is only valid as long as
+ * the policy is unmodifed.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *iter will be NULL.
+ */
+ extern int qpol_type_set_get_subtracted_types_iter(const qpol_policy_t * policy, const qpol_type_set_t * ts,
+ qpol_iterator_t ** iter);
+
+/**
+ * Determine if a type set includes '*'.
+ * @param policy Policy associated with the type set.
+ * @param ts Type set to check for '*'.
+ * @param is_star Pointer to integer to set.
+ * Will be set to 1 if ts contains '*' or 0 otherwise.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *is_star will be 0.
+ */
+ extern int qpol_type_set_get_is_star(const qpol_policy_t * policy, const qpol_type_set_t * ts, uint32_t * is_star);
+
+/**
+ * Determine if a type set is complemented (contains '~').
+ * @param policy Policy associated with the type set.
+ * @param ts Type set to check for complement.
+ * @param is_comp Pointer to integer to set.
+ * Will be set to 1 if ts is complemented or 0 otherwise.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *is_comp will be 0.
+ */
+ extern int qpol_type_set_get_is_comp(const qpol_policy_t * policy, const qpol_type_set_t * ts, uint32_t * is_comp);
+
+/**
+ * Get the rule type of a syntactic avrule.
+ * @param policy Policy associated with the rule.
+ * @param rule Avrule from which to get the type.
+ * @param rule_type Pointer to integer to set.
+ * Will be one of QPOL_RULE_* (see qpol/avrule_query.h).
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *rule_type will be 0.
+ */
+ extern int qpol_syn_avrule_get_rule_type(const qpol_policy_t * policy, const qpol_syn_avrule_t * rule,
+ uint32_t * rule_type);
+
+/**
+ * Get the set of types specified for a syntatic rule's source field.
+ * @param policy Policy associated with the rule.
+ * @param rule Avrule from which to get the source type set.
+ * @param source_set Type set returned; the caller <b>should not</b>
+ * free this pointer.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *source_set will be NULL.
+ */
+ extern int qpol_syn_avrule_get_source_type_set(const qpol_policy_t * policy, const qpol_syn_avrule_t * rule,
+ const qpol_type_set_t ** source_set);
+
+/**
+ * Get the set of types specified for a syntactic rule's target field.
+ * @param policy Policy associated with the rule.
+ * @param rule Avrule from which to get the target type set.
+ * @param target_set Type set returned; the caller <b>should not</b>
+ * free this pointer.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *target_set will be NULL.
+ */
+ extern int qpol_syn_avrule_get_target_type_set(const qpol_policy_t * policy, const qpol_syn_avrule_t * rule,
+ const qpol_type_set_t ** target_set);
+
+/**
+ * Determine if a syntactic rule includes the self flag in the target set.
+ * @param policy Policy associated with the rule.
+ * @param rule Avrule to check for the self flag.
+ * @param is_self Pointer to the integer to set; if the rule includes self,
+ * this will be set to 1, otherwise it will be set to 0.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *is_self will be 0.
+ */
+ extern int qpol_syn_avrule_get_is_target_self(const qpol_policy_t * policy, const qpol_syn_avrule_t * rule,
+ uint32_t * is_self);
+
+/**
+ * Get an iterator over all classes specified in a syntactic rule.
+ * @param policy Policy associated with the rule.
+ * @param rule The rule from which to get the classes.
+ * @param classes Iterator over items of type qpol_class_t* returned.
+ * The caller is responsible for calling qpol_iterator_destroy()
+ * to free memory used by this iterator.
+ * It is important to note that this iterator is only valid as long as
+ * the policy is unmodifed.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *classes will be NULL.
+ */
+ extern int qpol_syn_avrule_get_class_iter(const qpol_policy_t * policy, const qpol_syn_avrule_t * rule,
+ qpol_iterator_t ** classes);
+
+/**
+ * Get an iterator over all permissions specified in a syntactic rule.
+ * @param policy Policy associated with the
+ * @param rule The rule from which to get the permissions.
+ * @param perms Iterator over items of type char* returned.
+ * The caller is responsible for calling qpol_iterator_destroy()
+ * to free memory used by this iterator.
+ * It is important to note that this iterator is only valid as long as
+ * the policy is unmodifed.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *perms will be NULL.
+ */
+ extern int qpol_syn_avrule_get_perm_iter(const qpol_policy_t * policy, const qpol_syn_avrule_t * rule,
+ qpol_iterator_t ** perms);
+
+/**
+ * Get the line number of a syntactic rule.
+ * @param policy Policy associated with the rule
+ * @param rule The rule for which to get the line number.
+ * @param lineno Pointer to set to the line number.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *lineno will be 0.
+ */
+ extern int qpol_syn_avrule_get_lineno(const qpol_policy_t * policy, const qpol_syn_avrule_t * rule, unsigned long *lineno);
+
+/**
+ * If the syntactic rule is within a conditional, then get that
+ * conditional and assign it to cond. Otherwise assign to cond NULL.
+ * @param policy Policy associated with the rule.
+ * @param rule The rule for which to get the conditional.
+ * @param cond Reference pointer to this rule's conditional
+ * expression, or NULL if the rule is unconditional.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *lineno will be 0.
+ */
+ extern int qpol_syn_avrule_get_cond(const qpol_policy_t * policy, const qpol_syn_avrule_t * rule,
+ const qpol_cond_t ** cond);
+
+/**
+ * Determine if the syntactic rule is enabled. Unconditional rules
+ * are always enabled.
+ * @param policy Policy associated with the rule.
+ * @param rule The rule for which to get the conditional.
+ * @param is_enabled Integer in which to store the result: set to 1
+ * if enabled and 0 otherwise.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *lineno will be 0.
+ */
+ extern int qpol_syn_avrule_get_is_enabled(const qpol_policy_t * policy, const qpol_syn_avrule_t * rule,
+ uint32_t * is_enabled);
+
+/**
+ * Get the rule type of a syntactic terule.
+ * @param policy Policy associated with the rule.
+ * @param rule Terule from which to get the type.
+ * @param rule_type Pointer to integer to set.
+ * Will be one of QPOL_RULE_TYPE_* (see qpol/terule_query.h).
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *rule_type will be 0.
+ */
+ extern int qpol_syn_terule_get_rule_type(const qpol_policy_t * policy, const qpol_syn_terule_t * rule,
+ uint32_t * rule_type);
+
+/**
+ * Bet the set of types specified for a syntactic rule's source field.
+ * @param policy Policy associated with the rule.
+ * @param rule Terule from which to get the source type set.
+ * @param source_set Type set returned; the caller <b>shoule not</b>
+ * free this pointer.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *source_set will be NULL.
+ */
+ extern int qpol_syn_terule_get_source_type_set(const qpol_policy_t * policy, const qpol_syn_terule_t * rule,
+ const qpol_type_set_t ** source_set);
+
+/**
+ * Get the set of types specified for a syntactic rule's target field.
+ * @param policy Policy associated with the rule.
+ * @param rule Terule from which to get the target types et.
+ * @param target_set Type set returned; ther caller <b>should not</b>
+ * free this pointer.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *target_set will be NULL.
+ */
+ extern int qpol_syn_terule_get_target_type_set(const qpol_policy_t * policy, const qpol_syn_terule_t * rule,
+ const qpol_type_set_t ** target_set);
+
+/**
+ * Get an iterator over all classes specified in a syntactic rule.
+ * @param policy Policy associated with the rule.
+ * @param rule The rule from which to get the classes.
+ * @param classes Iterator over items of type qpol_class_t* returned.
+ * The caller is responsible for calling qpol_iterator_destroy()
+ * to free memory used by this iterator.
+ * It is important to note that this iterator is only valid as long as
+ * the policy is unmodifed.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *classes will be NULL.
+ */
+ extern int qpol_syn_terule_get_class_iter(const qpol_policy_t * policy, const qpol_syn_terule_t * rule,
+ qpol_iterator_t ** classes);
+
+/* forward declaration */
+ struct qpol_type;
+
+/**
+ * Get the default type of a syntactic terule.
+ * @param policy Policy associated with the rule.
+ * @param rule Terule from which to et the default type.
+ * @param dflt Reference pointer to the type to return.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *dflt will be NULL.
+ */
+ extern int qpol_syn_terule_get_default_type(const qpol_policy_t * policy, const qpol_syn_terule_t * rule,
+ const struct qpol_type **dflt);
+
+/**
+ * Get the line number of a syntactic rule.
+ * @param policy Policy associated with the rule.
+ * @param rule The rule for which to get the line number.
+ * @param lineno Pointer to set to the line number.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *lineno will be 0.
+ */
+ extern int qpol_syn_terule_get_lineno(const qpol_policy_t * policy, const qpol_syn_terule_t * rule, unsigned long *lineno);
+
+/**
+ * If the syntactic rule is within a conditional, then get that
+ * conditional and assign it to cond. Otherwise assign to cond NULL.
+ * @param policy Policy associated with the rule.
+ * @param rule The rule for which to get the conditional.
+ * @param cond Reference pointer to this rule's conditional
+ * expression, or NULL if the rule is unconditional.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *lineno will be 0.
+ */
+ extern int qpol_syn_terule_get_cond(const qpol_policy_t * policy, const qpol_syn_terule_t * rule,
+ const qpol_cond_t ** cond);
+
+/**
+ * Determine if the syntactic rule is enabled. Unconditional rules
+ * are always enabled.
+ * @param policy Policy associated with the rule.
+ * @param rule The rule for which to get the conditional.
+ * @param is_enabled Integer in which to store the result: set to 1
+ * if enabled and 0 otherwise.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *lineno will be 0.
+ */
+ extern int qpol_syn_terule_get_is_enabled(const qpol_policy_t * policy, const qpol_syn_terule_t * rule,
+ uint32_t * is_enabled);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* QPOL_SYN_RULE_QUERY_H */
diff --git a/libqpol/include/qpol/terule_query.h b/libqpol/include/qpol/terule_query.h
new file mode 100644
index 0000000..0006d1a
--- /dev/null
+++ b/libqpol/include/qpol/terule_query.h
@@ -0,0 +1,159 @@
+/**
+ * @file
+ * Defines the public interface for searching and iterating over type rules.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @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
+ */
+
+#ifndef QPOL_TERULE_QUERY_H
+#define QPOL_TERULE_QUERY_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <qpol/policy.h>
+#include <qpol/cond_query.h>
+
+ typedef struct qpol_terule qpol_terule_t;
+
+/* rule type defines (values copied from "sepol/policydb/policydb.h") */
+#define QPOL_RULE_TYPE_TRANS 16
+#define QPOL_RULE_TYPE_CHANGE 64
+#define QPOL_RULE_TYPE_MEMBER 32
+
+/**
+ * Get an iterator over all type rules in a policy of a rule type in
+ * rule_type_mask. It is an error to call this function if rules are not
+ * loaded.
+ * @param policy Policy from which to get the av rules.
+ * @param rule_type_mask Bitwise or'ed set of QPOL_RULE_TYPE_* values.
+ * It is an error to specify any other values of QPOL_RULE_* in the mask.
+ * @param iter Iterator over items of type qpol_terule_t returned.
+ * The caller is responsible for calling qpol_iterator_destroy()
+ * to free memory used by this iterator.
+ * It is important to note that this iterator is only valid as long as
+ * the policy is unmodifed.
+ * @returm 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *iter will be NULL.
+ */
+ extern int qpol_policy_get_terule_iter(const qpol_policy_t * policy, uint32_t rule_type_mask, qpol_iterator_t ** iter);
+
+/**
+ * Get the source type from a type rule.
+ * @param policy Policy from which the rule comes.
+ * @param rule The rule from which to get the source type.
+ * @param source Pointer in which to store the source type.
+ * The caller should not free this pointer.
+ * @returm 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *source will be NULL.
+ */
+ extern int qpol_terule_get_source_type(const qpol_policy_t * policy, const qpol_terule_t * rule,
+ const qpol_type_t ** source);
+
+/**
+ * Get the target type from a type rule.
+ * @param policy Policy from which the rule comes.
+ * @param rule The rule from which to get the target type.
+ * @param target Pointer in which to store the target type.
+ * The caller should not free this pointer.
+ * @returm 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *target will be NULL.
+ */
+ extern int qpol_terule_get_target_type(const qpol_policy_t * policy, const qpol_terule_t * rule,
+ const qpol_type_t ** target);
+
+/**
+ * Get the object class from a type rule.
+ * @param policy Policy from which the rule comes.
+ * @param rule The rule from which to get the object class.
+ * @param obj_class Pointer in which to store the object class.
+ * The caller should not free this pointer.
+ * @returm 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *obj_class will be NULL.
+ */
+ extern int qpol_terule_get_object_class(const qpol_policy_t * policy, const qpol_terule_t * rule,
+ const qpol_class_t ** obj_class);
+
+/**
+ * Get the default type from a type rule.
+ * @param policy Policy from which the rule comes.
+ * @param rule The rule from which to get the default type.
+ * @param dflt Pointer in which to store the default type.
+ * The caller should not free this pointer.
+ * @returm 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *dflt will be NULL.
+ */
+ extern int qpol_terule_get_default_type(const qpol_policy_t * policy, const qpol_terule_t * rule,
+ const qpol_type_t ** dflt);
+
+/**
+ * Get the rule type value for a type rule.
+ * @param policy Policy from which the rule comes.
+ * @param rule The rule from which to get the rule type.
+ * @param rule_type Integer in which to store the rule type value.
+ * The value will be one of the QPOL_RULE_* values above.
+ * @returm 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *rule_type will be 0.
+ */
+ extern int qpol_terule_get_rule_type(const qpol_policy_t * policy, const qpol_terule_t * rule, uint32_t * rule_type);
+
+/**
+ * Get the conditional from which a type rule comes. If the rule
+ * is not a conditional rule *cond is set to NULL.
+ * @param policy Policy from which the rule comes.
+ * @param rule The rule from which to get the conditional.
+ * @param cond The conditional returned. (NULL if rule is not conditional)
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *cond will be NULL. If the rule is not conditional
+ * *cond is set to NULL and the function is considered successful.
+ */
+ extern int qpol_terule_get_cond(const qpol_policy_t * policy, const qpol_terule_t * rule, const qpol_cond_t ** cond);
+
+/**
+ * Determine if a rule is enabled. Unconditional rules are always enabled.
+ * @param policy Policy from which the rule comes.
+ * @param rule The rule to check.
+ * @param is_enabled Integer in which to store the result: set to 1 if enabled
+ * and 0 otherwise.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *is_enabled will be 0.
+ */
+ extern int qpol_terule_get_is_enabled(const qpol_policy_t * policy, const qpol_terule_t * rule, uint32_t * is_enabled);
+
+/**
+ * Get the list (true or false) in which a conditional rule is. It is
+ * an error to call this function for an unconditional rule.
+ * @param policy Policy from which the rule comes.
+ * @param rule The rule to check.
+ * @param which_list Integer in which to store the result: set to 1 if
+ * rule is in the true list or 0 if in the false list.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *which_list will be 0.
+ */
+ extern int qpol_terule_get_which_list(const qpol_policy_t * policy, const qpol_terule_t * rule, uint32_t * which_list);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libqpol/include/qpol/type_query.h b/libqpol/include/qpol/type_query.h
new file mode 100644
index 0000000..9537f25
--- /dev/null
+++ b/libqpol/include/qpol/type_query.h
@@ -0,0 +1,175 @@
+ /**
+ * @file
+ * Defines the public interface for searching and iterating over types.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2006-2008 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
+ */
+
+#ifndef QPOL_TYPE_QUERY_H
+#define QPOL_TYPE_QUERY_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stddef.h>
+#include <stdint.h>
+#include <qpol/iterator.h>
+#include <qpol/policy.h>
+
+ typedef struct qpol_type qpol_type_t;
+
+/**
+ * Get the datum for a type by name.
+ * @param policy The policy from which to get the type.
+ * @param name The name of the type; searching is case sensitive.
+ * @param datum Pointer in which to store the type datum; the caller
+ * should not free this pointer.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *datum will be NULL.
+ */
+ extern int qpol_policy_get_type_by_name(const qpol_policy_t * policy, const char *name, const qpol_type_t ** datum);
+
+/**
+ * Get an iterator for types (including attributes and aliases)
+ * declared in the policy.
+ * @param policy The policy from which to create the iterator.
+ * @param iter Iterator of type qpol_type_t* returned;
+ * the caller is responsible for calling qpol_iterator_destroy to
+ * free memory used; it is important to note that the iterator is
+ * valid only as long as the policy is unchanged.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *iter will be NULL.
+ */
+ extern int qpol_policy_get_type_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter);
+
+/**
+ * Get the integer value associated with a type. Values range from 1
+ * to the number of types declared in the policy.
+ * @param policy The policy associated with the type.
+ * @param datum The type from which to get the value.
+ * @param value Pointer to the integer in which to store value.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and value will be 0.
+ */
+ extern int qpol_type_get_value(const qpol_policy_t * policy, const qpol_type_t * datum, uint32_t * value);
+
+/**
+ * Determine whether a given type is an alias for another type.
+ * @param policy The policy associated with the type.
+ * @param datum The type to check.
+ * @param isalias Pointer to be set to 1 (true) if the type is an alias
+ * and 0 (false) otherwise.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *isalias will be 0 (false).
+ */
+ extern int qpol_type_get_isalias(const qpol_policy_t * policy, const qpol_type_t * datum, unsigned char *isalias);
+
+/**
+ * Determine whether a given type is an attribute.
+ * @param policy The policy associated with the type.
+ * @param datum The type to check.
+ * @param isattr Pointer to be set to 1 (true) if the type is an
+ * attribute and 0 (false) otherwise.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *isattr will be 0 (false).
+ */
+ extern int qpol_type_get_isattr(const qpol_policy_t * policy, const qpol_type_t * datum, unsigned char *isattr);
+
+/**
+ * Determine whether a given type has been marked as enforcing
+ * (default) or as permissive. If the policy does not support
+ * permissive types, then all types are enforcing. Attributes are
+ * always enforcing.
+ *
+ * @param policy The policy associated with the type.
+ * @param datum The type to check.
+ * @param ispermissive Pointer to be set to 1 (true) if the type is
+ * permissive and 0 (false) otherwise.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *ispermissive will be 0 (false).
+ */
+ extern int qpol_type_get_ispermissive(const qpol_policy_t * policy, const qpol_type_t * datum, unsigned char *ispermissive);
+
+/**
+ * Get an iterator for the list of types in an attribute.
+ * @param policy The policy associated with the attribute.
+ * @param datum The attribute from which to get the types.
+ * @param types Iterator of type qpol_type_t* returned;
+ * the caller is responsible for calling qpol_iterator_destroy to
+ * free memory used; it is important to note that the iterator is
+ * valid only as long as the policy is unchanged.
+ * @return Returns 0 on success, > 0 if the type is not an attribute
+ * and < 0 on failure; if the call fails, errno will be set and
+ * *types will be NULL. If the type is not an attribute *types will
+ * be NULL.
+ */
+ extern int qpol_type_get_type_iter(const qpol_policy_t * policy, const qpol_type_t * datum, qpol_iterator_t ** types);
+
+/**
+ * Get an iterator for the list of attributes given to a type.
+ * @param policy The policy associated with the type.
+ * @param datum The type for which to get the attributes.
+ * @param attrs Iterator of type qpol_type_t* returned;
+ * the caller is responsible for calling qpol_iterator_destroy to
+ * free memory used; it is important to note that the iterator is
+ * valid only as long as the policy is unchanged.
+ * @return Returns 0 on success, > 0 if the type is an attribute
+ * and < 0 on failure; if the call fails, errno will be set and
+ * *types will be NULL. If the type is an attribute *types will
+ * be NULL.
+ */
+ extern int qpol_type_get_attr_iter(const qpol_policy_t * policy, const qpol_type_t * datum, qpol_iterator_t ** attrs);
+
+/**
+ * Get the name by which a type is identified from its datum.
+ * @param policy The policy associated with the type.
+ * @param datum The type for which to get the name.
+ * @param name Pointer in which to store the name; the caller
+ * should not free the string. If the type is an alias then the
+ * primary name will be returned.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *name will be NULL.
+ */
+ extern int qpol_type_get_name(const qpol_policy_t * policy, const qpol_type_t * datum, const char **name);
+
+/**
+ * Get an iterator for the list of aliases for a type. If the given
+ * type is an alias, this returns an iterator of its primary type's
+ * aliases.
+ * @param policy The policy associated with the type.
+ * @param datum The type for which to get aliases.
+ * @param aliases Iterator of type char* returned; the caller is
+ * responsible for calling qpol_iterator_destroy to free
+ * memory used; it is important to note that the iterator is valid
+ * only as long as the policy is unchanged. If a type has no aliases,
+ * the iterator will be at end and have size 0.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *aliases will be NULL.
+ */
+ extern int qpol_type_get_alias_iter(const qpol_policy_t * policy, const qpol_type_t * datum, qpol_iterator_t ** aliases);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* QPOL_TYPE_QUERY_H */
diff --git a/libqpol/include/qpol/user_query.h b/libqpol/include/qpol/user_query.h
new file mode 100644
index 0000000..be6322d
--- /dev/null
+++ b/libqpol/include/qpol/user_query.h
@@ -0,0 +1,130 @@
+/**
+ * @file
+ * Defines the public interface for searching and iterating over users.
+ *
+ * @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
+ */
+
+#ifndef QPOL_USER_QUERY_H
+#define QPOL_USER_QUERY_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stddef.h>
+#include <stdint.h>
+#include <qpol/iterator.h>
+#include <qpol/policy.h>
+#include <qpol/mls_query.h>
+
+ typedef struct qpol_user qpol_user_t;
+
+/**
+ * Get the datum for a user by name.
+ * @param policy The policy from which to get the user.
+ * @param name The name of the user; searching is case sensitive.
+ * @param datum Pointer in which to store the user datum; the caller
+ * should not free this pointer.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and and *datum will be NULL.
+ */
+ extern int qpol_policy_get_user_by_name(const qpol_policy_t * policy, const char *name, const qpol_user_t ** datum);
+
+/**
+ * Get an iterator for users declared in the policy.
+ * @param policy The policy from which to create the iterator.
+ * @param iter Iterator of type qpol_user_t* returned;
+ * the caller is responsible for calling qpol_iterator_destroy to
+ * free memory used; it is important to note that the iterator is
+ * valid only as long as the policy is unchanged.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *iter will be NULL.
+ */
+ extern int qpol_policy_get_user_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter);
+
+/**
+ * Get the integer value associated with a user. Values range from 1 to
+ * the number of users declared in the policy.
+ * @param policy The policy associate with the user.
+ * @param datum The user from which to get the value.
+ * @param value Pointer to the integer to set to value.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and value will be 0.
+ */
+ extern int qpol_user_get_value(const qpol_policy_t * policy, const qpol_user_t * datum, uint32_t * value);
+
+/**
+ * Get an iterator for the set of roles assigned to a user.
+ * @param policy The policy associated with the user.
+ * @param datum The user from which to get the roles.
+ * @param roles Iterator of type qpol_role_t* returned;
+ * the caller is responsible for calling qpol_iterator_destroy to
+ * free memory used; it is important to note that the iterator is
+ * valid only as long as the policy is unchanged.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *roles will be NULL.
+ */
+ extern int qpol_user_get_role_iter(const qpol_policy_t * policy, const qpol_user_t * datum, qpol_iterator_t ** roles);
+
+/**
+ * Get the allowed MLS range of a user. If the policy is not MLS
+ * then the returned level will be NULL.
+ * @param policy The policy associated with the user.
+ * @param datum The user from which to get the range.
+ * @param range Pointer in which to store the range. If the policy
+ * is not MLS then NULL will be assigned to the pointer. The caller
+ * should not free this pointer.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *range will be NULL.
+ */
+ extern int qpol_user_get_range(const qpol_policy_t * policy, const qpol_user_t * datum, const qpol_mls_range_t ** range);
+
+/**
+ * Get the default level for a user. If the policy is not MLS then
+ * the returned level will be NULL.
+ * @param policy The policy associated with the user.
+ * @param datum The user from which to get the level.
+ * @param level Pointer in which to store the level. If the policy
+ * is not MLS then NULL will be assigned to the pointer. The caller
+ * should not free this pointer.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *level will be NULL.
+ */
+ extern int qpol_user_get_dfltlevel(const qpol_policy_t * policy, const qpol_user_t * datum,
+ const qpol_mls_level_t ** level);
+
+/**
+ * Get the name which identifies a user from its datum.
+ * @param policy The policy associated with the user.
+ * @param datum The user for which to get the name.
+ * @param name Pointer in which to store the name; the caller
+ * should not free this string.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and *name will be NULL.
+ */
+ extern int qpol_user_get_name(const qpol_policy_t * policy, const qpol_user_t * datum, const char **name);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* QPOL_USER_QUERY_H */
diff --git a/libqpol/include/qpol/util.h b/libqpol/include/qpol/util.h
new file mode 100644
index 0000000..f779c8e
--- /dev/null
+++ b/libqpol/include/qpol/util.h
@@ -0,0 +1,61 @@
+/**
+ * @file
+ *
+ * Miscellaneous, uncategorized functions for libqpol.
+ *
+ * @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
+ */
+
+#ifndef QPOL_UTIL_H
+#define QPOL_UTIL_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ * Return an immutable string describing this library's version.
+ *
+ * @return String describing this library.
+ */
+ extern const char *libqpol_get_version(void);
+
+/**
+ * Find the "default" policy file on the currently running system.
+ * First try looking for a monolithic source policy; if that does not
+ * exist then try a monolithic binary policy.
+ *
+ * @param path Buffer to store the policy's path. The caller is
+ * responsible for free()ing this string.
+ *
+ * @return 0 if a policy was found, > 0 if not, < 0 upon error.
+ */
+ extern int qpol_default_policy_find(char **path);
+
+/* bunzip() a file to '*data', returning the total number of uncompressed bytes
+ * in the file. Returns -1 if file could not be decompressed. */
+ extern ssize_t qpol_bunzip(FILE *f, char **data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libqpol/src/Makefile.am b/libqpol/src/Makefile.am
new file mode 100644
index 0000000..34d87a6
--- /dev/null
+++ b/libqpol/src/Makefile.am
@@ -0,0 +1,89 @@
+sepol_srcdir = @sepol_srcdir@
+
+lib_LIBRARIES = libqpol.a
+qpolso_DATA = libqpol.so.@libqpol_version@
+qpolsodir = $(libdir)
+
+tmp_sepol = ./tmp_sepol
+
+AM_YFLAGS = -d
+BUILT_SOURCES = policy_parse.h
+
+# search in sepol_srcdir/include before system's sepol directory
+AM_CFLAGS = @DEBUGCFLAGS@ @WARNCFLAGS@ @PROFILECFLAGS@ \
+ -I$(srcdir)/../include -I$(sepol_srcdir)/../include @SELINUX_CFLAGS@ -fpic
+AM_LDFLAGS = @DEBUGLDFLAGS@ @WARNLDFLAGS@ @PROFILELDFLAGS@
+
+libqpol_a_SOURCES = \
+ avrule_query.c \
+ bool_query.c \
+ class_perm_query.c \
+ cond_query.c \
+ constraint_query.c \
+ context_query.c \
+ expand.c \
+ expand.h \
+ fs_use_query.c \
+ genfscon_query.c \
+ isid_query.c \
+ iterator.c \
+ iterator_internal.h \
+ mls_query.c \
+ mlsrule_query.c \
+ module.c \
+ module_compiler.c module_compiler.h \
+ netifcon_query.c \
+ nodecon_query.c \
+ permissive_query.c \
+ polcap_query.c \
+ policy.c \
+ policy_define.c policy_define.h \
+ policy_extend.c \
+ policy_parse.h \
+ portcon_query.c \
+ qpol_internal.h \
+ queue.c queue.h \
+ rbacrule_query.c \
+ role_query.c \
+ syn_rule_internal.h \
+ syn_rule_query.c \
+ terule_query.c \
+ type_query.c \
+ user_query.c \
+ util.c \
+ policy_parse.y policy_scan.l
+libqpol_a_DEPENDENCIES = $(tmp_sepol)
+libqpol_a_LIBADD = $(tmp_sepol)/*.o
+
+libqpol_so_OBJS = $(patsubst %.c,%.o,$(filter %.c,$(libqpol_a_SOURCES))) policy_parse.o policy_scan.o
+LIBQPOL_SONAME = @libqpol_soname@
+
+dist_noinst_DATA = libqpol.map
+
+$(tmp_sepol): $(sepol_srcdir)/libsepol.a
+ mkdir -p $@
+ rm -f $@/*
+ cp $< $@
+ (cd $@; ar x libsepol.a)
+
+$(qpolso_DATA): $(tmp_sepol) $(libqpol_so_OBJS) libqpol.map
+ $(CC) -shared -o $@ $(libqpol_so_OBJS) $(AM_LDFLAGS) $(LDFLAGS) -Wl,-soname,$(LIBQPOL_SONAME),--version-script=$(srcdir)/libqpol.map,-z,defs -Wl,--whole-archive $(sepol_srcdir)/libsepol.a -Wl,--no-whole-archive @SELINUX_LIB_FLAG@ -lselinux -lsepol -lbz2
+ $(LN_S) -f $@ @libqpol_soname@
+ $(LN_S) -f $@ libqpol.so
+
+libqpol.so: $(qpolso_DATA)
+
+install-data-hook:
+ cd $(DESTDIR)$(qpolsodir) && $(LN_S) -f $(qpolso_DATA) @libqpol_soname@
+ cd $(DESTDIR)$(qpolsodir) && $(LN_S) -f $(qpolso_DATA) libqpol.so
+
+CLEANFILES = policy_parse.h policy_scan.c policy_parse.c
+
+clean-local:
+ -rm -rf $(tmp_sepol)
+
+mostlyclean-local:
+ -rm -rf *.gcno *.gcda *.gprof *.gcov libqpol.so @libqpol_soname@ $(qpolso_DATA)
+
+uninstall-local:
+ -rm -rf $(DESTDIR)$(qpolsodir)/$(qpolso_DATA) $(DESTDIR)$(qpolsodir)/@libqpol_soname@ $(DESTDIR)$(qpolsodir)/libqpol.so
diff --git a/libqpol/src/avrule_query.c b/libqpol/src/avrule_query.c
new file mode 100644
index 0000000..749565b
--- /dev/null
+++ b/libqpol/src/avrule_query.c
@@ -0,0 +1,288 @@
+ /**
+ * @file
+ * Implementation for the public interface for searching and iterating over avrules.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @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
+ */
+
+#include "iterator_internal.h"
+#include <qpol/iterator.h>
+#include <qpol/policy.h>
+#include <qpol/avrule_query.h>
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/avtab.h>
+#include <sepol/policydb/util.h>
+#include <stdlib.h>
+#include "qpol_internal.h"
+
+int qpol_policy_get_avrule_iter(const qpol_policy_t * policy, uint32_t rule_type_mask, qpol_iterator_t ** iter)
+{
+ policydb_t *db;
+ avtab_state_t *state;
+
+ if (iter) {
+ *iter = NULL;
+ }
+ if (policy == NULL || iter == NULL) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+#if 1 // Seems to make sediff/sediffx work better without breaking things
+ if (!qpol_policy_has_capability(policy, QPOL_CAP_RULES_LOADED)) {
+ ERR(policy, "%s", "Cannot get avrules: Rules not loaded");
+ errno = ENOTSUP;
+ return STATUS_ERR;
+ }
+#endif
+
+ if ((rule_type_mask & QPOL_RULE_NEVERALLOW) && !qpol_policy_has_capability(policy, QPOL_CAP_NEVERALLOW)) {
+ ERR(policy, "%s", "Cannot get avrules: Neverallow rules requested but not available");
+ errno = ENOTSUP;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+
+ state = calloc(1, sizeof(avtab_state_t));
+ if (state == NULL) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return STATUS_ERR;
+ }
+ state->ucond_tab = &db->te_avtab;
+ state->cond_tab = &db->te_cond_avtab;
+ state->rule_type_mask = rule_type_mask;
+ state->node = db->te_avtab.htable[0];
+
+ if (qpol_iterator_create
+ (policy, state, avtab_state_get_cur, avtab_state_next, avtab_state_end, avtab_state_size, free, iter)) {
+ free(state);
+ return STATUS_ERR;
+ }
+ if (state->node == NULL || !(state->node->key.specified & state->rule_type_mask)) {
+ avtab_state_next(*iter);
+ }
+ return STATUS_SUCCESS;
+}
+
+int qpol_avrule_get_source_type(const qpol_policy_t * policy, const qpol_avrule_t * rule, const qpol_type_t ** source)
+{
+ policydb_t *db = NULL;
+ avtab_ptr_t avrule = NULL;
+
+ if (source) {
+ *source = NULL;
+ }
+
+ if (!policy || !rule || !source) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+ avrule = (avtab_ptr_t) rule;
+
+ *source = (qpol_type_t *) db->type_val_to_struct[avrule->key.source_type - 1];
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_avrule_get_target_type(const qpol_policy_t * policy, const qpol_avrule_t * rule, const qpol_type_t ** target)
+{
+ policydb_t *db = NULL;
+ avtab_ptr_t avrule = NULL;
+
+ if (target) {
+ *target = NULL;
+ }
+
+ if (!policy || !rule || !target) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+ avrule = (avtab_ptr_t) rule;
+
+ *target = (qpol_type_t *) db->type_val_to_struct[avrule->key.target_type - 1];
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_avrule_get_object_class(const qpol_policy_t * policy, const qpol_avrule_t * rule, const qpol_class_t ** obj_class)
+{
+ policydb_t *db = NULL;
+ avtab_ptr_t avrule = NULL;
+
+ if (obj_class) {
+ *obj_class = NULL;
+ }
+
+ if (!policy || !rule || !obj_class) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+ avrule = (avtab_ptr_t) rule;
+
+ *obj_class = (qpol_class_t *) db->class_val_to_struct[avrule->key.target_class - 1];
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_avrule_get_perm_iter(const qpol_policy_t * policy, const qpol_avrule_t * rule, qpol_iterator_t ** perms)
+{
+ policydb_t *db = NULL;
+ avtab_ptr_t avrule = NULL;
+ perm_state_t *ps = NULL;
+
+ if (perms) {
+ *perms = NULL;
+ }
+
+ if (!policy || !rule || !perms) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+ avrule = (avtab_ptr_t) rule;
+ ps = calloc(1, sizeof(perm_state_t));
+ if (!ps) {
+ return STATUS_ERR;
+ }
+ if (avrule->key.specified & QPOL_RULE_DONTAUDIT) {
+ ps->perm_set = ~(avrule->datum.data); /* stored as auditdeny flip the bits */
+ } else {
+ ps->perm_set = avrule->datum.data;
+ }
+ ps->obj_class_val = avrule->key.target_class;
+
+ if (qpol_iterator_create(policy, (void *)ps, perm_state_get_cur,
+ perm_state_next, perm_state_end, perm_state_size, free, perms)) {
+ return STATUS_ERR;
+ }
+
+ if (!(ps->perm_set & 1)) /* defaults to bit 0, if off: advance */
+ perm_state_next(*perms);
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_avrule_get_rule_type(const qpol_policy_t * policy, const qpol_avrule_t * rule, uint32_t * rule_type)
+{
+ policydb_t *db = NULL;
+ avtab_ptr_t avrule = NULL;
+
+ if (rule_type) {
+ *rule_type = 0;
+ }
+
+ if (!policy || !rule || !rule_type) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+ avrule = (avtab_ptr_t) rule;
+
+ *rule_type =
+ (avrule->key.specified & (QPOL_RULE_ALLOW | QPOL_RULE_NEVERALLOW | QPOL_RULE_AUDITALLOW | QPOL_RULE_DONTAUDIT));
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_avrule_get_cond(const qpol_policy_t * policy, const qpol_avrule_t * rule, const qpol_cond_t ** cond)
+{
+ avtab_ptr_t avrule = NULL;
+
+ if (cond) {
+ *cond = NULL;
+ }
+
+ if (!policy || !rule || !cond) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ avrule = (avtab_ptr_t) rule;
+
+ *cond = (qpol_cond_t *) avrule->parse_context;
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_avrule_get_is_enabled(const qpol_policy_t * policy, const qpol_avrule_t * rule, uint32_t * is_enabled)
+{
+ avtab_ptr_t avrule = NULL;
+
+ if (is_enabled) {
+ *is_enabled = 0;
+ }
+
+ if (!policy || !rule || !is_enabled) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ avrule = (avtab_ptr_t) rule;
+
+ *is_enabled = ((avrule->merged & QPOL_COND_RULE_ENABLED) ? 1 : 0);
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_avrule_get_which_list(const qpol_policy_t * policy, const qpol_avrule_t * rule, uint32_t * which_list)
+{
+ avtab_ptr_t avrule = NULL;
+
+ if (which_list) {
+ *which_list = 0;
+ }
+
+ if (!policy || !rule || !which_list) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ avrule = (avtab_ptr_t) rule;
+
+ if (!avrule->parse_context) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ *which_list = ((avrule->merged & QPOL_COND_RULE_LIST) ? 1 : 0);
+
+ return STATUS_SUCCESS;
+}
diff --git a/libqpol/src/bool_query.c b/libqpol/src/bool_query.c
new file mode 100644
index 0000000..8814a59
--- /dev/null
+++ b/libqpol/src/bool_query.c
@@ -0,0 +1,193 @@
+/**
+ * @file
+ * Implementation of the interface for searching and iterating over booleans.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @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
+ */
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <qpol/iterator.h>
+#include <sepol/policydb.h>
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/expand.h>
+#include "iterator_internal.h"
+#include <qpol/bool_query.h>
+#include "qpol_internal.h"
+
+int qpol_policy_get_bool_by_name(const qpol_policy_t * policy, const char *name, qpol_bool_t ** datum)
+{
+ hashtab_datum_t internal_datum;
+ policydb_t *db;
+
+ if (policy == NULL || name == NULL || datum == NULL) {
+ if (datum != NULL)
+ *datum = NULL;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+ internal_datum = hashtab_search(db->p_bools.table, (const hashtab_key_t)name);
+ if (internal_datum == NULL) {
+ ERR(policy, "could not find datum for bool %s", name);
+ *datum = NULL;
+ errno = ENOENT;
+ return STATUS_ERR;
+ }
+ *datum = (qpol_bool_t *) internal_datum;
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_policy_get_bool_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter)
+{
+ policydb_t *db;
+ hash_state_t *hs = NULL;
+ int error = 0;
+
+ if (policy == NULL || iter == NULL) {
+ if (iter != NULL)
+ *iter = NULL;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+
+ hs = calloc(1, sizeof(hash_state_t));
+ if (hs == NULL) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = error;
+ return STATUS_ERR;
+ }
+ hs->table = &db->p_bools.table;
+ hs->node = (*(hs->table))->htable[0];
+
+ if (qpol_iterator_create(policy, (void *)hs, hash_state_get_cur,
+ hash_state_next, hash_state_end, hash_state_size, free, iter)) {
+ free(hs);
+ return STATUS_ERR;
+ }
+
+ if (hs->node == NULL)
+ hash_state_next(*iter);
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_bool_get_value(const qpol_policy_t * policy, const qpol_bool_t * datum, uint32_t * value)
+{
+ cond_bool_datum_t *internal_datum;
+
+ if (policy == NULL || datum == NULL || value == NULL) {
+ if (value != NULL)
+ *value = 0;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_datum = (cond_bool_datum_t *) datum;
+ *value = internal_datum->s.value;
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_bool_get_state(const qpol_policy_t * policy, const qpol_bool_t * datum, int *state)
+{
+ cond_bool_datum_t *internal_datum;
+
+ if (policy == NULL || datum == NULL || state == NULL) {
+ if (state != NULL)
+ *state = 0;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_datum = (cond_bool_datum_t *) datum;
+ *state = internal_datum->state;
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_bool_set_state(qpol_policy_t * policy, qpol_bool_t * datum, int state)
+{
+ cond_bool_datum_t *internal_datum;
+
+ if (policy == NULL || datum == NULL) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_datum = (cond_bool_datum_t *) datum;
+ internal_datum->state = state;
+
+ /* re-evaluate conditionals to update the state of their rules */
+ if (qpol_policy_reevaluate_conds(policy)) {
+ return STATUS_ERR; /* errno already set */
+ }
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_bool_set_state_no_eval(qpol_policy_t * policy, qpol_bool_t * datum, int state)
+{
+ cond_bool_datum_t *internal_datum;
+
+ if (policy == NULL || datum == NULL) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_datum = (cond_bool_datum_t *) datum;
+ internal_datum->state = state;
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_bool_get_name(const qpol_policy_t * policy, const qpol_bool_t * datum, const char **name)
+{
+ cond_bool_datum_t *internal_datum = NULL;
+ policydb_t *db = NULL;
+
+ if (policy == NULL || datum == NULL || name == NULL) {
+ if (name != NULL)
+ *name = NULL;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+ internal_datum = (cond_bool_datum_t *) datum;
+
+ *name = db->p_bool_val_to_name[internal_datum->s.value - 1];
+
+ return STATUS_SUCCESS;
+}
diff --git a/libqpol/src/class_perm_query.c b/libqpol/src/class_perm_query.c
new file mode 100644
index 0000000..f63e1d4
--- /dev/null
+++ b/libqpol/src/class_perm_query.c
@@ -0,0 +1,653 @@
+/**
+ * @file
+ * Implementation of the interface for searching and iterating over
+ * classes, commons, and permissions.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @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
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <qpol/iterator.h>
+#include <sepol/policydb.h>
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/expand.h>
+#include "iterator_internal.h"
+#include <qpol/class_perm_query.h>
+#include "qpol_internal.h"
+
+/* perms */
+typedef struct perm_hash_state
+{
+ unsigned int bucket;
+ hashtab_node_t *node;
+ hashtab_t *table;
+ const char *perm_name;
+} perm_hash_state_t;
+
+static int hash_state_next_class_w_perm(qpol_iterator_t * iter)
+{
+ class_datum_t *internal_class = NULL;
+ qpol_iterator_t *internal_perms = NULL;
+ unsigned char has_perm = 0;
+ perm_hash_state_t *hs = NULL;
+ sepol_policydb_t sp;
+ qpol_policy_t qp;
+ char *tmp = NULL;
+
+ hs = (perm_hash_state_t *) qpol_iterator_state(iter);
+ if (hs == NULL) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ if (hs->bucket >= (*(hs->table))->size) {
+ errno = ERANGE;
+ return STATUS_ERR;
+ }
+
+ /* shallow copy ok here as only internal values are used */
+ sp.p = *qpol_iterator_policy(iter);
+ qp.p = &sp;
+ qp.fn = NULL;
+
+ do {
+ hash_state_next(iter);
+ if (hash_state_end(iter))
+ break;
+ internal_class = hs->node ? (class_datum_t *) hs->node->datum : NULL;
+ qpol_class_get_perm_iter(&qp, (qpol_class_t *) internal_class, &internal_perms);
+ for (; !qpol_iterator_end(internal_perms); qpol_iterator_next(internal_perms)) {
+ qpol_iterator_get_item(internal_perms, (void **)&tmp);
+ if (!strcmp(tmp, hs->perm_name)) {
+ has_perm = 1;
+ break;
+ }
+ }
+ qpol_iterator_destroy(&internal_perms);
+ } while (!has_perm && !hash_state_end(iter));
+
+ return STATUS_SUCCESS;
+}
+
+static size_t hash_perm_state_size_common(const qpol_iterator_t * iter)
+{
+ perm_hash_state_t *hs = NULL;
+ uint32_t tmp_bucket = 0;
+ size_t count = 0;
+ hashtab_node_t *tmp_node;
+ sepol_policydb_t sp;
+ qpol_policy_t qp;
+ qpol_iterator_t *internal_perms;
+ common_datum_t *internal_common;
+ char *tmp = NULL;
+
+ if (iter == NULL || qpol_iterator_state(iter) == NULL) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+ hs = (perm_hash_state_t *) qpol_iterator_state(iter);
+ if (hs == NULL) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+ /* shallow copy ok here as only internal values are used */
+ sp.p = *qpol_iterator_policy(iter);
+ if (&sp.p == NULL) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+ qp.p = &sp;
+ qp.fn = NULL;
+ for (tmp_bucket = 0; tmp_bucket < (*(hs->table))->size; tmp_bucket++) {
+ for (tmp_node = (*(hs->table))->htable[tmp_bucket]; tmp_node; tmp_node = tmp_node->next) {
+ internal_common = tmp_node ? ((common_datum_t *) tmp_node->datum) : NULL;
+ qpol_common_get_perm_iter(&qp, (qpol_common_t *) internal_common, &internal_perms);
+ for (; !qpol_iterator_end(internal_perms); qpol_iterator_next(internal_perms)) {
+ qpol_iterator_get_item(internal_perms, (void **)&tmp);
+ if (!strcmp(tmp, hs->perm_name)) {
+ count++;
+ break;
+ }
+ }
+ qpol_iterator_destroy(&internal_perms);
+ }
+ }
+
+ return count;
+}
+
+static size_t hash_perm_state_size_class(const qpol_iterator_t * iter)
+{
+ perm_hash_state_t *hs = NULL;
+ uint32_t tmp_bucket = 0;
+ size_t count = 0;
+ hashtab_node_t *tmp_node;
+ sepol_policydb_t sp;
+ qpol_policy_t qp;
+ qpol_iterator_t *internal_perms;
+ class_datum_t *internal_class;
+ char *tmp = NULL;
+
+ if (iter == NULL || qpol_iterator_state(iter) == NULL) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+ hs = (perm_hash_state_t *) qpol_iterator_state(iter);
+ if (hs == NULL) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+ /* shallow copy ok here as only internal values are used */
+ sp.p = *qpol_iterator_policy(iter);
+ qp.p = &sp;
+ qp.fn = NULL;
+ if (&sp.p == NULL) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+ for (tmp_bucket = 0; tmp_bucket < (*(hs->table))->size; tmp_bucket++) {
+ for (tmp_node = (*(hs->table))->htable[tmp_bucket]; tmp_node; tmp_node = tmp_node->next) {
+ internal_class = tmp_node ? ((class_datum_t *) tmp_node->datum) : NULL;
+ qpol_class_get_perm_iter(&qp, (qpol_class_t *) internal_class, &internal_perms);
+ for (; !qpol_iterator_end(internal_perms); qpol_iterator_next(internal_perms)) {
+ qpol_iterator_get_item(internal_perms, (void **)&tmp);
+ if (!strcmp(tmp, hs->perm_name)) {
+ count++;
+ break;
+ }
+ }
+ qpol_iterator_destroy(&internal_perms);
+ }
+ }
+
+ return count;
+}
+
+static int hash_state_next_common_w_perm(qpol_iterator_t * iter)
+{
+ common_datum_t *internal_common = NULL;
+ qpol_iterator_t *internal_perms = NULL;
+ unsigned char has_perm = 0;
+ perm_hash_state_t *hs = NULL;
+ sepol_policydb_t sp;
+ qpol_policy_t qp;
+ char *tmp = NULL;
+
+ hs = (perm_hash_state_t *) qpol_iterator_state(iter);
+ if (hs == NULL) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ if (hs->bucket >= (*(hs->table))->size) {
+ errno = ERANGE;
+ return STATUS_ERR;
+ }
+
+ /* shallow copy ok here as only internal values are used */
+ sp.p = *qpol_iterator_policy(iter);
+ qp.p = &sp;
+ qp.fn = NULL;
+
+ do {
+ hash_state_next(iter);
+ if (hash_state_end(iter))
+ break;
+ internal_common = hs->node ? (common_datum_t *) hs->node->datum : NULL;
+ qpol_common_get_perm_iter(&qp, (qpol_common_t *) internal_common, &internal_perms);
+ for (; !qpol_iterator_end(internal_perms); qpol_iterator_next(internal_perms)) {
+ qpol_iterator_get_item(internal_perms, (void **)&tmp);
+ if (!strcmp(tmp, hs->perm_name)) {
+ has_perm = 1;
+ break;
+ }
+ }
+ qpol_iterator_destroy(&internal_perms);
+ } while (!has_perm && !hash_state_end(iter));
+
+ return STATUS_SUCCESS;
+}
+
+static int qpol_class_has_perm(const qpol_policy_t * p, const qpol_class_t * class, const char *perm)
+{
+ qpol_iterator_t *iter = NULL;
+ char *tmp;
+
+ qpol_class_get_perm_iter(p, class, &iter);
+ for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
+ qpol_iterator_get_item(iter, (void **)&tmp);
+ if (!strcmp(perm, tmp)) {
+ qpol_iterator_destroy(&iter);
+ return 1;
+ }
+ }
+ qpol_iterator_destroy(&iter);
+ return 0;
+}
+
+static int qpol_common_has_perm(const qpol_policy_t * p, const qpol_common_t * common, const char *perm)
+{
+ qpol_iterator_t *iter = NULL;
+ char *tmp;
+
+ qpol_common_get_perm_iter(p, common, &iter);
+ for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
+ qpol_iterator_get_item(iter, (void **)&tmp);
+ if (!strcmp(perm, tmp)) {
+ qpol_iterator_destroy(&iter);
+ return 1;
+ }
+ }
+ qpol_iterator_destroy(&iter);
+ return 0;
+}
+
+int qpol_perm_get_class_iter(const qpol_policy_t * policy, const char *perm, qpol_iterator_t ** classes)
+{
+ policydb_t *db;
+ int error = 0;
+ perm_hash_state_t *hs = NULL;
+
+ if (policy == NULL || classes == NULL) {
+ if (classes != NULL)
+ *classes = NULL;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+
+ hs = calloc(1, sizeof(perm_hash_state_t));
+ if (hs == NULL) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = error;
+ return STATUS_ERR;
+ }
+ hs->table = &db->p_classes.table;
+ hs->node = (*(hs->table))->htable[0];
+ hs->perm_name = perm;
+
+ if (qpol_iterator_create(policy, (void *)hs, hash_state_get_cur,
+ hash_state_next_class_w_perm, hash_state_end, hash_perm_state_size_class, free, classes)) {
+ free(hs);
+ return STATUS_ERR;
+ }
+
+ if (hs->node == NULL || !qpol_class_has_perm(policy, (qpol_class_t *) hs->node->datum, perm))
+ hash_state_next_class_w_perm(*classes);
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_perm_get_common_iter(const qpol_policy_t * policy, const char *perm, qpol_iterator_t ** commons)
+{
+ policydb_t *db;
+ int error = 0;
+ perm_hash_state_t *hs = NULL;
+
+ if (policy == NULL || commons == NULL) {
+ if (commons != NULL)
+ *commons = NULL;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+
+ hs = calloc(1, sizeof(perm_hash_state_t));
+ if (hs == NULL) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = error;
+ return STATUS_ERR;
+ }
+ hs->table = &db->p_commons.table;
+ hs->node = (*(hs->table))->htable[0];
+ hs->perm_name = perm;
+
+ if (qpol_iterator_create(policy, (void *)hs, hash_state_get_cur,
+ hash_state_next_common_w_perm, hash_state_end, hash_perm_state_size_common, free, commons)) {
+ free(hs);
+ return STATUS_ERR;
+ }
+
+ if (hs->node == NULL || !qpol_common_has_perm(policy, (qpol_common_t *) hs->node->datum, perm))
+ hash_state_next_common_w_perm(*commons);
+
+ return STATUS_SUCCESS;
+}
+
+/* classes */
+int qpol_policy_get_class_by_name(const qpol_policy_t * policy, const char *name, const qpol_class_t ** obj_class)
+{
+ hashtab_datum_t internal_datum;
+ policydb_t *db;
+
+ if (policy == NULL || name == NULL || obj_class == NULL) {
+ if (obj_class != NULL)
+ *obj_class = NULL;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+ internal_datum = hashtab_search(db->p_classes.table, (const hashtab_key_t)name);
+ if (internal_datum == NULL) {
+ *obj_class = NULL;
+ ERR(policy, "could not find class %s", name);
+ errno = ENOENT;
+ return STATUS_ERR;
+ }
+
+ *obj_class = (qpol_class_t *) internal_datum;
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_policy_get_class_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter)
+{
+ policydb_t *db;
+ int error = 0;
+ hash_state_t *hs = NULL;
+
+ if (policy == NULL || iter == NULL) {
+ if (iter != NULL)
+ *iter = NULL;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+
+ hs = calloc(1, sizeof(hash_state_t));
+ if (hs == NULL) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = error;
+ return STATUS_ERR;
+ }
+ hs->table = &db->p_classes.table;
+ hs->node = (*(hs->table))->htable[0];
+
+ if (qpol_iterator_create(policy, (void *)hs, hash_state_get_cur,
+ hash_state_next, hash_state_end, hash_state_size, free, iter)) {
+ free(hs);
+ return STATUS_ERR;
+ }
+
+ if (hs->node == NULL)
+ hash_state_next(*iter);
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_class_get_value(const qpol_policy_t * policy, const qpol_class_t * obj_class, uint32_t * value)
+{
+ class_datum_t *internal_datum;
+
+ if (policy == NULL || obj_class == NULL || value == NULL) {
+ if (value != NULL)
+ *value = 0;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_datum = (class_datum_t *) obj_class;
+ *value = internal_datum->s.value;
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_class_get_common(const qpol_policy_t * policy, const qpol_class_t * obj_class, const qpol_common_t ** common)
+{
+ class_datum_t *internal_datum = NULL;
+
+ if (policy == NULL || obj_class == NULL || common == NULL) {
+ if (common != NULL)
+ *common = NULL;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_datum = (class_datum_t *) obj_class;
+ *common = (qpol_common_t *) internal_datum->comdatum;
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_class_get_perm_iter(const qpol_policy_t * policy, const qpol_class_t * obj_class, qpol_iterator_t ** perms)
+{
+ class_datum_t *internal_datum = NULL;
+ policydb_t *db = NULL;
+ int error = 0;
+ hash_state_t *hs = NULL;
+
+ if (policy == NULL || obj_class == NULL || perms == NULL) {
+ if (perms != NULL)
+ *perms = NULL;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_datum = (class_datum_t *) obj_class;
+ db = &policy->p->p;
+
+ hs = calloc(1, sizeof(hash_state_t));
+ if (hs == NULL) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = error;
+ return STATUS_ERR;
+ }
+ hs->table = &internal_datum->permissions.table;
+ if (hs->table && *(hs->table)) {
+ hs->node = (*(hs->table))->htable[0];
+ } else { /* object class has no permissions */
+ hs->node = NULL;
+ }
+
+ if (qpol_iterator_create(policy, (void *)hs, hash_state_get_cur_key,
+ hash_state_next, hash_state_end, hash_state_size, free, perms)) {
+ free(hs);
+ return STATUS_ERR;
+ }
+
+ if (hs->node == NULL)
+ hash_state_next(*perms);
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_class_get_name(const qpol_policy_t * policy, const qpol_class_t * obj_class, const char **name)
+{
+ class_datum_t *internal_datum = NULL;
+ policydb_t *db = NULL;
+
+ if (policy == NULL || obj_class == NULL || name == NULL) {
+ if (name != NULL)
+ *name = NULL;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+ internal_datum = (class_datum_t *) obj_class;
+
+ *name = db->p_class_val_to_name[internal_datum->s.value - 1];
+
+ return STATUS_SUCCESS;
+}
+
+/* commons */
+int qpol_policy_get_common_by_name(const qpol_policy_t * policy, const char *name, const qpol_common_t ** common)
+{
+ hashtab_datum_t internal_datum;
+ policydb_t *db;
+
+ if (policy == NULL || name == NULL || common == NULL) {
+ if (common != NULL)
+ *common = NULL;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+ internal_datum = hashtab_search(db->p_commons.table, (const hashtab_key_t)name);
+ if (internal_datum == NULL) {
+ *common = NULL;
+ ERR(policy, "could not find common %s", name);
+ errno = ENOENT;
+ return STATUS_ERR;
+ }
+ *common = (qpol_common_t *) internal_datum;
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_policy_get_common_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter)
+{
+ policydb_t *db;
+ int error = 0;
+ hash_state_t *hs = NULL;
+
+ if (policy == NULL || iter == NULL) {
+ if (iter != NULL)
+ *iter = NULL;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+
+ hs = calloc(1, sizeof(hash_state_t));
+ if (hs == NULL) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = error;
+ return STATUS_ERR;
+ }
+ hs->table = &db->p_commons.table;
+ hs->node = (*(hs->table))->htable[0];
+
+ if (qpol_iterator_create(policy, (void *)hs, hash_state_get_cur,
+ hash_state_next, hash_state_end, hash_state_size, free, iter)) {
+ free(hs);
+ return STATUS_ERR;
+ }
+
+ if (hs->node == NULL)
+ hash_state_next(*iter);
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_common_get_value(const qpol_policy_t * policy, const qpol_common_t * common, uint32_t * value)
+{
+ common_datum_t *internal_datum;
+
+ if (policy == NULL || common == NULL || value == NULL) {
+ if (value != NULL)
+ *value = 0;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_datum = (common_datum_t *) common;
+ *value = internal_datum->s.value;
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_common_get_perm_iter(const qpol_policy_t * policy, const qpol_common_t * common, qpol_iterator_t ** perms)
+{
+ common_datum_t *internal_datum = NULL;
+ policydb_t *db = NULL;
+ int error = 0;
+ hash_state_t *hs = NULL;
+
+ if (policy == NULL || common == NULL || perms == NULL) {
+ if (perms != NULL)
+ *perms = NULL;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_datum = (common_datum_t *) common;
+ db = &policy->p->p;
+
+ hs = calloc(1, sizeof(hash_state_t));
+ if (hs == NULL) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = error;
+ return STATUS_ERR;
+ }
+ hs->table = &internal_datum->permissions.table;
+ hs->node = (*(hs->table))->htable[0];
+
+ if (qpol_iterator_create(policy, (void *)hs, hash_state_get_cur_key,
+ hash_state_next, hash_state_end, hash_state_size, free, perms)) {
+ free(hs);
+ return STATUS_ERR;
+ }
+
+ if (hs->node == NULL)
+ hash_state_next(*perms);
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_common_get_name(const qpol_policy_t * policy, const qpol_common_t * common, const char **name)
+{
+ common_datum_t *internal_datum = NULL;
+ policydb_t *db = NULL;
+
+ if (policy == NULL || common == NULL || name == NULL) {
+ if (name != NULL)
+ *name = NULL;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+ internal_datum = (common_datum_t *) common;
+
+ *name = db->p_common_val_to_name[internal_datum->s.value - 1];
+
+ return STATUS_SUCCESS;
+}
diff --git a/libqpol/src/cond_query.c b/libqpol/src/cond_query.c
new file mode 100644
index 0000000..4bd3adf
--- /dev/null
+++ b/libqpol/src/cond_query.c
@@ -0,0 +1,620 @@
+/**
+ * @file
+ * Implememtation for the public interface for searching and iterating
+ * conditionals
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @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
+ */
+
+#include <qpol/policy.h>
+#include <qpol/cond_query.h>
+#include <qpol/bool_query.h>
+#include <qpol/avrule_query.h>
+#include <qpol/terule_query.h>
+#include <qpol/iterator.h>
+#include "iterator_internal.h"
+#include "qpol_internal.h"
+
+#include <sepol/policydb/conditional.h>
+
+#include <stdlib.h>
+#include <errno.h>
+
+typedef struct cond_state
+{
+ cond_node_t *head;
+ cond_node_t *cur;
+} cond_state_t;
+
+static int cond_state_end(const qpol_iterator_t * iter)
+{
+ cond_state_t *cs = NULL;
+
+ if (!iter || !(cs = (cond_state_t *) qpol_iterator_state(iter))) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ return cs->cur ? 0 : 1;
+}
+
+static void *cond_state_get_cur(const qpol_iterator_t * iter)
+{
+ cond_state_t *cs = NULL;
+
+ if (!iter || !(cs = (cond_state_t *) qpol_iterator_state(iter)) || qpol_iterator_end(iter)) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ return cs->cur;
+}
+
+static int cond_state_next(qpol_iterator_t * iter)
+{
+ cond_state_t *cs = NULL;
+
+ if (!iter || !(cs = (cond_state_t *) qpol_iterator_state(iter))) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ if (qpol_iterator_end(iter)) {
+ errno = ERANGE;
+ return STATUS_ERR;
+ }
+
+ cs->cur = cs->cur->next;
+
+ return STATUS_SUCCESS;
+}
+
+static size_t cond_state_size(const qpol_iterator_t * iter)
+{
+ cond_state_t *cs = NULL;
+ cond_node_t *tmp = NULL;
+ size_t count = 0;
+
+ if (!iter || !(cs = (cond_state_t *) qpol_iterator_state(iter))) {
+ errno = EINVAL;
+ return 0;
+ }
+
+ for (tmp = cs->head; tmp; tmp = tmp->next)
+ count++;
+
+ return count;
+}
+
+int qpol_policy_get_cond_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter)
+{
+ int error = 0;
+ cond_state_t *cs = NULL;
+ policydb_t *db = NULL;
+
+ if (iter)
+ *iter = NULL;
+
+ if (!policy || !iter) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ if (!qpol_policy_has_capability(policy, QPOL_CAP_RULES_LOADED)) {
+ ERR(policy, "%s", "Cannot get conditionals: Rules not loaded");
+ errno = ENOTSUP;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+
+ if (!(cs = calloc(1, sizeof(cond_state_t)))) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto err;
+ }
+ cs->head = cs->cur = db->cond_list;
+
+ if (qpol_iterator_create(policy, (void *)cs,
+ cond_state_get_cur, cond_state_next, cond_state_end, cond_state_size, free, iter)) {
+ error = errno;
+ goto err;
+ }
+
+ return STATUS_SUCCESS;
+
+ err:
+ free(cs);
+ errno = error;
+ return STATUS_ERR;
+}
+
+typedef struct cond_expr_state
+{
+ cond_expr_t *head;
+ cond_expr_t *cur;
+} cond_expr_state_t;
+
+static int cond_expr_state_end(const qpol_iterator_t * iter)
+{
+ cond_expr_state_t *ces = NULL;
+
+ if (!iter || !(ces = (cond_expr_state_t *) qpol_iterator_state(iter))) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ return ces->cur ? 0 : 1;
+}
+
+static void *cond_expr_state_get_cur(const qpol_iterator_t * iter)
+{
+ cond_expr_state_t *ces = NULL;
+
+ if (!iter || !(ces = (cond_expr_state_t *) qpol_iterator_state(iter)) || qpol_iterator_end(iter)) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ return ces->cur;
+}
+
+static int cond_expr_state_next(qpol_iterator_t * iter)
+{
+ cond_expr_state_t *ces = NULL;
+
+ if (!iter || !(ces = (cond_expr_state_t *) qpol_iterator_state(iter))) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ if (qpol_iterator_end(iter)) {
+ errno = ERANGE;
+ return STATUS_ERR;
+ }
+
+ ces->cur = ces->cur->next;
+
+ return STATUS_SUCCESS;
+}
+
+static size_t cond_expr_state_size(const qpol_iterator_t * iter)
+{
+ cond_expr_state_t *ces = NULL;
+ cond_expr_t *tmp = NULL;
+ size_t count = 0;
+
+ if (!iter || !(ces = (cond_expr_state_t *) qpol_iterator_state(iter))) {
+ errno = EINVAL;
+ return 0;
+ }
+
+ for (tmp = ces->head; tmp; tmp = tmp->next)
+ count++;
+
+ return count;
+}
+
+int qpol_cond_get_expr_node_iter(const qpol_policy_t * policy, const qpol_cond_t * cond, qpol_iterator_t ** iter)
+{
+ int error = 0;
+ cond_expr_state_t *ces = NULL;
+ cond_node_t *internal_cond = NULL;
+ policydb_t *db = NULL;
+
+ if (iter)
+ *iter = NULL;
+
+ if (!policy || !cond || !iter) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+ internal_cond = (cond_node_t *) cond;
+
+ if (!(ces = calloc(1, sizeof(cond_expr_state_t)))) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto err;
+ }
+ ces->head = ces->cur = internal_cond->expr;
+
+ if (qpol_iterator_create(policy, (void *)ces,
+ cond_expr_state_get_cur, cond_expr_state_next, cond_expr_state_end,
+ cond_expr_state_size, free, iter)) {
+ error = errno;
+ goto err;
+ }
+
+ return STATUS_SUCCESS;
+
+ err:
+ free(ces);
+ errno = error;
+ return STATUS_ERR;
+}
+
+typedef struct cond_rule_state
+{
+ cond_av_list_t *head;
+ cond_av_list_t *cur;
+ uint32_t rule_type_mask;
+} cond_rule_state_t;
+
+static int cond_rule_state_end(const qpol_iterator_t * iter)
+{
+ cond_rule_state_t *crs = NULL;
+
+ if (!iter || !(crs = (cond_rule_state_t *) qpol_iterator_state(iter))) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ return crs->cur ? 0 : 1;
+}
+
+static void *cond_rule_state_get_cur(const qpol_iterator_t * iter)
+{
+ cond_rule_state_t *crs = NULL;
+
+ if (!iter || !(crs = (cond_rule_state_t *) qpol_iterator_state(iter)) || qpol_iterator_end(iter)) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ return crs->cur->node;
+}
+
+static int cond_rule_state_next(qpol_iterator_t * iter)
+{
+ cond_rule_state_t *crs = NULL;
+
+ if (!iter || !(crs = (cond_rule_state_t *) qpol_iterator_state(iter))) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ if (qpol_iterator_end(iter)) {
+ errno = ERANGE;
+ return STATUS_ERR;
+ }
+
+ do {
+ crs->cur = crs->cur->next;
+ } while (crs->cur && !(crs->cur->node->key.specified & crs->rule_type_mask));
+
+ return STATUS_SUCCESS;
+}
+
+static size_t cond_rule_state_size(const qpol_iterator_t * iter)
+{
+ cond_rule_state_t *crs = NULL;
+ cond_av_list_t *tmp = NULL;
+ size_t count = 0;
+
+ if (!iter || !(crs = (cond_rule_state_t *) qpol_iterator_state(iter))) {
+ errno = EINVAL;
+ return 0;
+ }
+
+ for (tmp = crs->head; tmp; tmp = tmp->next) {
+ if (tmp->node->key.specified & crs->rule_type_mask)
+ count++;
+ }
+
+ return count;
+}
+
+int qpol_cond_get_av_true_iter(const qpol_policy_t * policy, const qpol_cond_t * cond, uint32_t rule_type_mask,
+ qpol_iterator_t ** iter)
+{
+ int error = 0;
+ cond_rule_state_t *crs = NULL;
+ cond_node_t *internal_cond = NULL;
+ policydb_t *db = NULL;
+
+ if (iter)
+ *iter = NULL;
+
+ if (!policy || !cond || !iter) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ if (rule_type_mask & ~(QPOL_RULE_ALLOW | QPOL_RULE_NEVERALLOW | QPOL_RULE_AUDITALLOW | QPOL_RULE_DONTAUDIT)) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+ internal_cond = (cond_node_t *) cond;
+
+ if (!(crs = calloc(1, sizeof(cond_rule_state_t)))) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto err;
+ }
+ crs->head = crs->cur = internal_cond->true_list;
+ crs->rule_type_mask = rule_type_mask;
+
+ if (qpol_iterator_create(policy, (void *)crs,
+ cond_rule_state_get_cur, cond_rule_state_next, cond_rule_state_end,
+ cond_rule_state_size, free, iter)) {
+ error = errno;
+ goto err;
+ }
+
+ if (crs->cur && !(crs->cur->node->key.specified & crs->rule_type_mask))
+ qpol_iterator_next(*iter);
+
+ return STATUS_SUCCESS;
+
+ err:
+ free(crs);
+ errno = error;
+ return STATUS_ERR;
+}
+
+int qpol_cond_get_te_true_iter(const qpol_policy_t * policy, const qpol_cond_t * cond, uint32_t rule_type_mask,
+ qpol_iterator_t ** iter)
+{
+ int error = 0;
+ cond_rule_state_t *crs = NULL;
+ cond_node_t *internal_cond = NULL;
+ policydb_t *db = NULL;
+
+ if (iter)
+ *iter = NULL;
+
+ if (!policy || !cond || !iter) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ if (rule_type_mask & ~(QPOL_RULE_TYPE_TRANS | QPOL_RULE_TYPE_CHANGE | QPOL_RULE_TYPE_MEMBER)) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+ internal_cond = (cond_node_t *) cond;
+
+ if (!(crs = calloc(1, sizeof(cond_rule_state_t)))) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto err;
+ }
+ crs->head = crs->cur = internal_cond->true_list;
+ crs->rule_type_mask = rule_type_mask;
+
+ if (qpol_iterator_create(policy, (void *)crs,
+ cond_rule_state_get_cur, cond_rule_state_next, cond_rule_state_end,
+ cond_rule_state_size, free, iter)) {
+ error = errno;
+ goto err;
+ }
+
+ if (crs->cur && !(crs->cur->node->key.specified & crs->rule_type_mask))
+ qpol_iterator_next(*iter);
+
+ return STATUS_SUCCESS;
+
+ err:
+ free(crs);
+ errno = error;
+ return STATUS_ERR;
+}
+
+int qpol_cond_get_av_false_iter(const qpol_policy_t * policy, const qpol_cond_t * cond, uint32_t rule_type_mask,
+ qpol_iterator_t ** iter)
+{
+ int error = 0;
+ cond_rule_state_t *crs = NULL;
+ cond_node_t *internal_cond = NULL;
+ policydb_t *db = NULL;
+
+ if (iter)
+ *iter = NULL;
+
+ if (!policy || !cond || !iter) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ if (rule_type_mask & ~(QPOL_RULE_ALLOW | QPOL_RULE_NEVERALLOW | QPOL_RULE_AUDITALLOW | QPOL_RULE_DONTAUDIT)) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+ internal_cond = (cond_node_t *) cond;
+
+ if (!(crs = calloc(1, sizeof(cond_rule_state_t)))) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto err;
+ }
+ crs->head = crs->cur = internal_cond->false_list;
+ crs->rule_type_mask = rule_type_mask;
+
+ if (qpol_iterator_create(policy, (void *)crs,
+ cond_rule_state_get_cur, cond_rule_state_next, cond_rule_state_end,
+ cond_rule_state_size, free, iter)) {
+ error = errno;
+ goto err;
+ }
+
+ if (crs->cur && !(crs->cur->node->key.specified & crs->rule_type_mask))
+ qpol_iterator_next(*iter);
+
+ return STATUS_SUCCESS;
+
+ err:
+ free(crs);
+ errno = error;
+ return STATUS_ERR;
+}
+
+int qpol_cond_get_te_false_iter(const qpol_policy_t * policy, const qpol_cond_t * cond, uint32_t rule_type_mask,
+ qpol_iterator_t ** iter)
+{
+ int error = 0;
+ cond_rule_state_t *crs = NULL;
+ cond_node_t *internal_cond = NULL;
+ policydb_t *db = NULL;
+
+ if (iter)
+ *iter = NULL;
+
+ if (!policy || !cond || !iter) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ if (rule_type_mask & ~(QPOL_RULE_TYPE_TRANS | QPOL_RULE_TYPE_CHANGE | QPOL_RULE_TYPE_MEMBER)) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+ internal_cond = (cond_node_t *) cond;
+
+ if (!(crs = calloc(1, sizeof(cond_rule_state_t)))) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto err;
+ }
+ crs->head = crs->cur = internal_cond->false_list;
+ crs->rule_type_mask = rule_type_mask;
+
+ if (qpol_iterator_create(policy, (void *)crs,
+ cond_rule_state_get_cur, cond_rule_state_next, cond_rule_state_end,
+ cond_rule_state_size, free, iter)) {
+ error = errno;
+ goto err;
+ }
+
+ if (crs->cur && !(crs->cur->node->key.specified & crs->rule_type_mask))
+ qpol_iterator_next(*iter);
+
+ return STATUS_SUCCESS;
+
+ err:
+ free(crs);
+ errno = error;
+ return STATUS_ERR;
+}
+
+int qpol_cond_eval(const qpol_policy_t * policy, const qpol_cond_t * cond, uint32_t * is_true)
+{
+ int error = 0;
+ cond_node_t *internal_cond = NULL;
+
+ if (is_true)
+ *is_true = 0;
+
+ if (!policy || !cond || !is_true) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_cond = (cond_node_t *) cond;
+
+ if ((*is_true = (uint32_t) cond_evaluate_expr(&policy->p->p, internal_cond->expr)) > 1) {
+ error = ERANGE;
+ goto err;
+ }
+
+ return STATUS_SUCCESS;
+
+ err:
+ ERR(policy, "%s", strerror(error));
+ errno = error;
+ return STATUS_ERR;
+}
+
+int qpol_cond_expr_node_get_expr_type(const qpol_policy_t * policy, const qpol_cond_expr_node_t * node, uint32_t * expr_type)
+{
+ cond_expr_t *internal_cond = NULL;
+
+ if (expr_type)
+ *expr_type = 0;
+
+ if (!policy || !node || !expr_type) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_cond = (cond_expr_t *) node;
+
+ *expr_type = internal_cond->expr_type;
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_cond_expr_node_get_bool(const qpol_policy_t * policy, const qpol_cond_expr_node_t * node, qpol_bool_t ** cond_bool)
+{
+ int error = 0;
+ cond_expr_t *internal_cond = NULL;
+ policydb_t *db = NULL;
+
+ if (cond_bool)
+ *cond_bool = NULL;
+
+ if (!policy || !node || !cond_bool) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+ internal_cond = (cond_expr_t *) node;
+
+ if (internal_cond->expr_type != QPOL_COND_EXPR_BOOL) {
+ error = EINVAL;
+ goto err;
+ }
+
+ if (!(*cond_bool = (qpol_bool_t *) db->bool_val_to_struct[internal_cond->bool - 1])) {
+ error = EINVAL;
+ goto err;
+ }
+
+ return STATUS_SUCCESS;
+
+ err:
+ ERR(policy, "%s", strerror(error));
+ errno = error;
+ return STATUS_ERR;
+}
diff --git a/libqpol/src/constraint_query.c b/libqpol/src/constraint_query.c
new file mode 100644
index 0000000..1545ad7
--- /dev/null
+++ b/libqpol/src/constraint_query.c
@@ -0,0 +1,983 @@
+/**
+ * @file
+ * Implementation of the public interface for searching and iterating over
+ * constraints
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @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
+ */
+
+#include <config.h>
+
+#include <qpol/policy.h>
+#include <qpol/constraint_query.h>
+#include <qpol/iterator.h>
+#include <qpol/class_perm_query.h>
+#include "qpol_internal.h"
+#include "iterator_internal.h"
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/constraint.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+struct qpol_constraint
+{
+ const qpol_class_t *obj_class;
+ constraint_node_t *constr;
+};
+
+typedef struct policy_constr_state
+{
+ qpol_iterator_t *class_iter;
+ qpol_iterator_t *constr_iter;
+ const qpol_policy_t *policy; /* needed to get sub iterators */
+} policy_constr_state_t;
+
+static int policy_constr_state_end(const qpol_iterator_t * iter)
+{
+ policy_constr_state_t *pcs = NULL;
+
+ if (!iter || !(pcs = (policy_constr_state_t *) qpol_iterator_state(iter))) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ return (qpol_iterator_end(pcs->class_iter) && qpol_iterator_end(pcs->constr_iter)) ? 1 : 0;
+}
+
+static void *policy_constr_state_get_cur(const qpol_iterator_t * iter)
+{
+ policy_constr_state_t *pcs = NULL;
+ void *tmp = NULL;
+
+ if (!iter || !(pcs = (policy_constr_state_t *) qpol_iterator_state(iter)) || qpol_iterator_end(iter)) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ if (qpol_iterator_get_item(pcs->constr_iter, &tmp)) {
+ return NULL;
+ }
+
+ return tmp;
+}
+
+static int policy_constr_state_next(qpol_iterator_t * iter)
+{
+ policy_constr_state_t *pcs = NULL;
+ qpol_class_t *obj_class = NULL;
+
+ if (!iter || !(pcs = (policy_constr_state_t *) qpol_iterator_state(iter))) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ if (qpol_iterator_end(iter)) {
+ errno = ERANGE;
+ return STATUS_ERR;
+ }
+
+ qpol_iterator_next(pcs->constr_iter);
+ while (qpol_iterator_end(pcs->constr_iter)) {
+ qpol_iterator_destroy(&pcs->constr_iter);
+ qpol_iterator_next(pcs->class_iter);
+ if (qpol_iterator_end(pcs->class_iter))
+ return STATUS_SUCCESS;
+ if (qpol_iterator_get_item(pcs->class_iter, (void **)&obj_class))
+ return STATUS_ERR;
+ if (qpol_class_get_constraint_iter(pcs->policy, obj_class, &pcs->constr_iter))
+ return STATUS_ERR;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+static size_t policy_constr_state_size(const qpol_iterator_t * iter)
+{
+ policy_constr_state_t *pcs = NULL;
+ qpol_class_t *obj_class = NULL;
+ qpol_iterator_t *internal_iter = NULL, *constr_iter = NULL;
+ size_t count = 0, tmp = 0;
+
+ if (!iter || !(pcs = (policy_constr_state_t *) qpol_iterator_state(iter))) {
+ errno = EINVAL;
+ return 0;
+ }
+
+ if (qpol_policy_get_class_iter(pcs->policy, &internal_iter))
+ return 0;
+
+ for (; !qpol_iterator_end(internal_iter); qpol_iterator_next(internal_iter)) {
+ if (qpol_iterator_get_item(internal_iter, (void **)&obj_class))
+ goto err;
+ if (qpol_class_get_constraint_iter(pcs->policy, obj_class, &constr_iter))
+ goto err;
+ if (qpol_iterator_get_size(constr_iter, &tmp))
+ goto err;
+ count += tmp;
+ tmp = 0;
+ qpol_iterator_destroy(&constr_iter);
+ }
+
+ qpol_iterator_destroy(&internal_iter);
+ return count;
+
+ err:
+ qpol_iterator_destroy(&internal_iter);
+ qpol_iterator_destroy(&constr_iter);
+ return 0;
+}
+
+static void policy_constr_state_free(void *x)
+{
+ policy_constr_state_t *pcs = (policy_constr_state_t *) x;
+
+ if (!pcs)
+ return;
+
+ qpol_iterator_destroy(&pcs->class_iter);
+ qpol_iterator_destroy(&pcs->constr_iter);
+ free(pcs);
+}
+
+int qpol_policy_get_constraint_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter)
+{
+ policy_constr_state_t *pcs = NULL;
+ int error = 0;
+ qpol_class_t *tmp = NULL;
+
+ if (iter)
+ *iter = NULL;
+
+ if (!policy || !iter) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ if (!(pcs = calloc(1, sizeof(policy_constr_state_t)))) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return STATUS_ERR;
+ }
+ pcs->policy = policy;
+ if (qpol_policy_get_class_iter(policy, &pcs->class_iter)) {
+ error = errno;
+ goto err;
+ }
+ if (qpol_iterator_get_item(pcs->class_iter, (void **)&tmp)) {
+ error = errno;
+ ERR(policy, "Error getting first class: %s", strerror(error));
+ goto err;
+ }
+ if (qpol_class_get_constraint_iter(policy, tmp, &pcs->constr_iter)) {
+ error = errno;
+ goto err;
+ }
+
+ if (qpol_iterator_create(policy, (void *)pcs,
+ policy_constr_state_get_cur, policy_constr_state_next,
+ policy_constr_state_end, policy_constr_state_size, policy_constr_state_free, iter)) {
+ error = errno;
+ goto err;
+ }
+
+ if (qpol_iterator_end(pcs->constr_iter)) {
+ if (qpol_iterator_next(*iter)) {
+ error = errno;
+ pcs = NULL; /* avoid double free, iterator will destroy this */
+ ERR(policy, "Error finding first constraint: %s", strerror(error));
+ goto err;
+ }
+ }
+
+ return STATUS_SUCCESS;
+
+ err:
+ policy_constr_state_free(pcs);
+ qpol_iterator_destroy(iter);
+ errno = error;
+ return STATUS_ERR;
+}
+
+int qpol_constraint_get_class(const qpol_policy_t * policy, const qpol_constraint_t * constr, const qpol_class_t ** obj_class)
+{
+ if (obj_class)
+ *obj_class = NULL;
+
+ if (!policy || !constr || !obj_class) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ *obj_class = constr->obj_class;
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_constraint_get_perm_iter(const qpol_policy_t * policy, const qpol_constraint_t * constr, qpol_iterator_t ** iter)
+{
+ perm_state_t *ps = NULL;
+ constraint_node_t *internal_constr = NULL;
+
+ if (iter)
+ *iter = NULL;
+
+ if (!policy || !constr || !iter) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_constr = (constraint_node_t *) constr->constr;
+
+ if (!(ps = calloc(1, sizeof(perm_state_t)))) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ }
+ ps->perm_set = internal_constr->permissions;
+ qpol_class_get_value(policy, constr->obj_class, &ps->obj_class_val);
+
+ if (qpol_iterator_create(policy, (void *)ps, perm_state_get_cur,
+ perm_state_next, perm_state_end, perm_state_size, free, iter)) {
+ free(ps);
+ return STATUS_ERR;
+ }
+
+ if (!(ps->perm_set & 1)) /* defaults to bit 0 */
+ qpol_iterator_next(*iter);
+
+ return STATUS_SUCCESS;
+}
+
+typedef struct constr_expr_state
+{
+ constraint_expr_t *head;
+ constraint_expr_t *cur;
+} constr_expr_state_t;
+
+static int constr_expr_state_end(const qpol_iterator_t * iter)
+{
+ constr_expr_state_t *ces = NULL;
+
+ if (!iter || !(ces = (constr_expr_state_t *) qpol_iterator_state(iter))) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ return ces->cur ? 0 : 1;
+}
+
+static void *constr_expr_state_get_cur(const qpol_iterator_t * iter)
+{
+ constr_expr_state_t *ces = NULL;
+
+ if (!iter || !(ces = (constr_expr_state_t *) qpol_iterator_state(iter)) || qpol_iterator_end(iter)) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ return ces->cur;
+}
+
+static int constr_expr_state_next(qpol_iterator_t * iter)
+{
+ constr_expr_state_t *ces = NULL;
+
+ if (!iter || !(ces = (constr_expr_state_t *) qpol_iterator_state(iter))) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ if (qpol_iterator_end(iter)) {
+ errno = ERANGE;
+ return STATUS_ERR;
+ }
+
+ ces->cur = ces->cur->next;
+
+ return STATUS_SUCCESS;
+}
+
+static size_t constr_expr_state_size(const qpol_iterator_t * iter)
+{
+ constr_expr_state_t *ces = NULL;
+ constraint_expr_t *tmp = NULL;
+ size_t count = 0;
+
+ if (!iter || !(ces = (constr_expr_state_t *) qpol_iterator_state(iter))) {
+ errno = EINVAL;
+ return 0;
+ }
+
+ for (tmp = ces->head; tmp; tmp = tmp->next)
+ count++;
+
+ return count;
+}
+
+int qpol_constraint_get_expr_iter(const qpol_policy_t * policy, const qpol_constraint_t * constr, qpol_iterator_t ** iter)
+{
+ constr_expr_state_t *ces = NULL;
+ constraint_node_t *internal_constr = NULL;
+
+ if (iter)
+ *iter = NULL;
+
+ if (!policy || !constr || !iter) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_constr = (constraint_node_t *) constr->constr;
+
+ if (!(ces = calloc(1, sizeof(constr_expr_state_t)))) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return STATUS_ERR;
+ }
+ ces->head = ces->cur = internal_constr->expr;
+
+ if (qpol_iterator_create(policy, (void *)ces,
+ constr_expr_state_get_cur, constr_expr_state_next,
+ constr_expr_state_end, constr_expr_state_size, free, iter)) {
+ free(ces);
+ return STATUS_ERR;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+static int policy_constr_state_next_vtrans(qpol_iterator_t * iter)
+{
+ policy_constr_state_t *pcs = NULL;
+ qpol_class_t *obj_class = NULL;
+
+ if (!iter || !(pcs = (policy_constr_state_t *) qpol_iterator_state(iter))) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ if (qpol_iterator_end(iter)) {
+ errno = ERANGE;
+ return STATUS_ERR;
+ }
+
+ qpol_iterator_next(pcs->constr_iter);
+ while (qpol_iterator_end(pcs->constr_iter)) {
+ qpol_iterator_destroy(&pcs->constr_iter);
+ qpol_iterator_next(pcs->class_iter);
+ if (qpol_iterator_end(pcs->class_iter))
+ return STATUS_SUCCESS;
+ if (qpol_iterator_get_item(pcs->class_iter, (void **)&obj_class))
+ return STATUS_ERR;
+ if (qpol_class_get_validatetrans_iter(pcs->policy, obj_class, &pcs->constr_iter))
+ return STATUS_ERR;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+static size_t policy_constr_state_size_vtrans(const qpol_iterator_t * iter)
+{
+ policy_constr_state_t *pcs = NULL;
+ qpol_class_t *obj_class = NULL;
+ qpol_iterator_t *internal_iter = NULL, *constr_iter = NULL;
+ size_t count = 0, tmp = 0;
+
+ if (!iter || !(pcs = (policy_constr_state_t *) qpol_iterator_state(iter))) {
+ errno = EINVAL;
+ return 0;
+ }
+
+ if (qpol_policy_get_class_iter(pcs->policy, &internal_iter))
+ return 0;
+
+ for (; !qpol_iterator_end(internal_iter); qpol_iterator_next(internal_iter)) {
+ if (qpol_iterator_get_item(internal_iter, (void **)&obj_class))
+ goto err;
+ if (qpol_class_get_validatetrans_iter(pcs->policy, obj_class, &constr_iter))
+ goto err;
+ if (qpol_iterator_get_size(constr_iter, &tmp))
+ goto err;
+ count += tmp;
+ tmp = 0;
+ qpol_iterator_destroy(&constr_iter);
+ }
+
+ qpol_iterator_destroy(&internal_iter);
+ return count;
+
+ err:
+ qpol_iterator_destroy(&internal_iter);
+ qpol_iterator_destroy(&constr_iter);
+ return 0;
+}
+
+int qpol_policy_get_validatetrans_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter)
+{
+ policy_constr_state_t *pcs = NULL;
+ int error = 0;
+ qpol_class_t *tmp = NULL;
+
+ if (iter)
+ *iter = NULL;
+
+ if (!policy || !iter) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ if (!(pcs = calloc(1, sizeof(policy_constr_state_t)))) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return STATUS_ERR;
+ }
+ pcs->policy = policy;
+ if (qpol_policy_get_class_iter(policy, &pcs->class_iter)) {
+ error = errno;
+ goto err;
+ }
+ if (qpol_iterator_get_item(pcs->class_iter, (void **)&tmp)) {
+ error = errno;
+ ERR(policy, "Error getting first class: %s", strerror(error));
+ goto err;
+ }
+ if (qpol_class_get_validatetrans_iter(policy, tmp, &pcs->constr_iter)) {
+ error = errno;
+ goto err;
+ }
+
+ if (qpol_iterator_create(policy, (void *)pcs,
+ policy_constr_state_get_cur, policy_constr_state_next_vtrans,
+ policy_constr_state_end, policy_constr_state_size_vtrans, policy_constr_state_free, iter)) {
+ error = errno;
+ goto err;
+ }
+
+ if (qpol_iterator_end(pcs->constr_iter)) {
+ if (qpol_iterator_next(*iter)) {
+ error = errno;
+ pcs = NULL; /* avoid double free, iterator will destroy this */
+ ERR(policy, "Error finding first validatetrans: %s", strerror(error));
+ goto err;
+ }
+ }
+
+ return STATUS_SUCCESS;
+
+ err:
+ policy_constr_state_free(pcs);
+ qpol_iterator_destroy(iter);
+ errno = error;
+ return STATUS_ERR;
+
+}
+
+int qpol_validatetrans_get_class(const qpol_policy_t * policy, const qpol_validatetrans_t * vtrans, const qpol_class_t ** obj_class)
+{
+ if (obj_class)
+ *obj_class = NULL;
+
+ if (!policy || !vtrans || !obj_class) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ *obj_class = ((qpol_constraint_t *) vtrans)->obj_class;
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_validatetrans_get_expr_iter(const qpol_policy_t * policy, const qpol_validatetrans_t * vtrans, qpol_iterator_t ** iter)
+{
+ constr_expr_state_t *ces = NULL;
+ constraint_node_t *internal_constr = NULL;
+
+ if (iter)
+ *iter = NULL;
+
+ if (!policy || !vtrans || !iter) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_constr = (constraint_node_t *) ((qpol_constraint_t *) vtrans)->constr;
+
+ if (!(ces = calloc(1, sizeof(constr_expr_state_t)))) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return STATUS_ERR;
+ }
+ ces->head = ces->cur = internal_constr->expr;
+
+ if (qpol_iterator_create(policy, (void *)ces,
+ constr_expr_state_get_cur, constr_expr_state_next,
+ constr_expr_state_end, constr_expr_state_size, free, iter)) {
+ free(ces);
+ return STATUS_ERR;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_constraint_expr_node_get_expr_type(const qpol_policy_t * policy, const qpol_constraint_expr_node_t * expr,
+ uint32_t * expr_type)
+{
+ constraint_expr_t *internal_expr = NULL;
+
+ if (!policy || !expr || !expr_type) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_expr = (constraint_expr_t *) expr;
+
+ *expr_type = internal_expr->expr_type;
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_constraint_expr_node_get_sym_type(const qpol_policy_t * policy, const qpol_constraint_expr_node_t * expr,
+ uint32_t * sym_type)
+{
+ constraint_expr_t *internal_expr = NULL;
+
+ if (!policy || !expr || !sym_type) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_expr = (constraint_expr_t *) expr;
+
+ *sym_type = internal_expr->attr;
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_constraint_expr_node_get_op(const qpol_policy_t * policy, const qpol_constraint_expr_node_t * expr, uint32_t * op)
+{
+ constraint_expr_t *internal_expr = NULL;
+
+ if (!policy || !expr || !op) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_expr = (constraint_expr_t *) expr;
+
+ *op = internal_expr->op;
+
+ return STATUS_SUCCESS;
+}
+
+typedef struct cexpr_name_state
+{
+ ebitmap_t *inc;
+ ebitmap_t *sub;
+ size_t cur;
+#define QPOL_CEXPR_NAME_STATE_INC_LIST 0
+#define QPOL_CEXPR_NAME_STATE_SUB_LIST 1
+ unsigned char list;
+} cexpr_name_state_t;
+
+static int cexpr_name_state_end(const qpol_iterator_t * iter)
+{
+ cexpr_name_state_t *cns = NULL;
+
+ if (!iter || !(cns = (cexpr_name_state_t *) qpol_iterator_state(iter))) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ if (cns->list == QPOL_CEXPR_NAME_STATE_SUB_LIST && (cns->sub ? cns->cur >= cns->sub->highbit : 1))
+ return 1;
+
+ return 0;
+}
+
+static int cexpr_name_state_next(qpol_iterator_t * iter)
+{
+ cexpr_name_state_t *cns = NULL;
+ ebitmap_t *bmap = NULL;
+
+ if (!iter || !(cns = (cexpr_name_state_t *) qpol_iterator_state(iter))) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ if (qpol_iterator_end(iter)) {
+ errno = ERANGE;
+ return STATUS_ERR;
+ }
+
+ bmap = (cns->list == QPOL_CEXPR_NAME_STATE_INC_LIST ? cns->inc : cns->sub);
+
+ do {
+ cns->cur++;
+ if (cns->cur >= bmap->highbit) {
+ if (cns->list == QPOL_CEXPR_NAME_STATE_INC_LIST) {
+ cns->list = QPOL_CEXPR_NAME_STATE_SUB_LIST;
+ cns->cur = 0;
+ bmap = cns->sub;
+ if (!bmap)
+ break;
+ } else {
+ break;
+ }
+ }
+ } while (!ebitmap_get_bit(bmap, cns->cur));
+
+ return STATUS_SUCCESS;
+}
+
+static size_t cexpr_name_state_size(const qpol_iterator_t * iter)
+{
+ cexpr_name_state_t *cns = NULL;
+ size_t count = 0, bit = 0;
+ ebitmap_node_t *node = NULL;
+
+ if (!iter || !(cns = (cexpr_name_state_t *) qpol_iterator_state(iter))) {
+ errno = EINVAL;
+ return 0;
+ }
+
+ ebitmap_for_each_bit(cns->inc, node, bit) {
+ count += ebitmap_get_bit(cns->inc, bit);
+ }
+
+ if (!(cns->sub))
+ return count;
+
+ bit = 0;
+ ebitmap_for_each_bit(cns->sub, node, bit) {
+ count += ebitmap_get_bit(cns->sub, bit);
+ }
+
+ return count;
+}
+
+static void *cexpr_name_state_get_cur_user(const qpol_iterator_t * iter)
+{
+ cexpr_name_state_t *cns = NULL;
+ const policydb_t *db = NULL;
+
+ if (!iter || !(cns = (cexpr_name_state_t *) qpol_iterator_state(iter)) ||
+ !(db = qpol_iterator_policy(iter)) || qpol_iterator_end(iter)) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ return strdup(db->p_user_val_to_name[cns->cur]);
+}
+
+static void *cexpr_name_state_get_cur_role(const qpol_iterator_t * iter)
+{
+ cexpr_name_state_t *cns = NULL;
+ const policydb_t *db = NULL;
+
+ if (!iter || !(cns = (cexpr_name_state_t *) qpol_iterator_state(iter)) ||
+ !(db = qpol_iterator_policy(iter)) || qpol_iterator_end(iter)) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ return strdup(db->p_role_val_to_name[cns->cur]);
+}
+
+static void *cexpr_name_state_get_cur_type(const qpol_iterator_t * iter)
+{
+ cexpr_name_state_t *cns = NULL;
+ const policydb_t *db = NULL;
+ char *tmp = NULL, *name = NULL;
+ size_t len = 0;
+
+ if (!iter || !(cns = (cexpr_name_state_t *) qpol_iterator_state(iter)) ||
+ !(db = qpol_iterator_policy(iter)) || qpol_iterator_end(iter)) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ tmp = strdup(db->p_type_val_to_name[cns->cur]);
+
+ if (cns->list == QPOL_CEXPR_NAME_STATE_INC_LIST)
+ return tmp;
+
+ len = strlen(tmp);
+ name = calloc(len + 2, sizeof(char));
+ if (!name) {
+ free(tmp);
+ errno = ENOMEM;
+ return NULL;
+ }
+ len++;
+
+ snprintf(name, len + 1, "-%s", tmp);
+ free(tmp);
+
+ return name;
+}
+
+int qpol_constraint_expr_node_get_names_iter(const qpol_policy_t * policy, const qpol_constraint_expr_node_t * expr,
+ qpol_iterator_t ** iter)
+{
+ constraint_expr_t *internal_expr = NULL;
+ cexpr_name_state_t *cns = NULL;
+ int policy_type = 0;
+
+ if (iter)
+ *iter = NULL;
+
+ if (!policy || !expr || !iter) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ if (qpol_policy_get_type(policy, &policy_type))
+ return STATUS_ERR;
+
+ internal_expr = (constraint_expr_t *) expr;
+
+ if (internal_expr->expr_type != QPOL_CEXPR_TYPE_NAMES) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ if (!(cns = calloc(1, sizeof(cexpr_name_state_t)))) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return STATUS_ERR;
+ }
+ if (internal_expr->attr & QPOL_CEXPR_SYM_TYPE) {
+ if (policy_type == QPOL_POLICY_KERNEL_BINARY) {
+ cns->inc = &(internal_expr->names);
+ } else {
+ cns->inc = &(internal_expr->type_names->types);
+ cns->sub = &(internal_expr->type_names->negset);
+ }
+ } else {
+ cns->inc = &(internal_expr->names);
+ }
+ cns->list = QPOL_CEXPR_NAME_STATE_INC_LIST;
+ cns->cur = cns->inc->node ? cns->inc->node->startbit : 0;
+
+ switch (internal_expr->attr & ~(QPOL_CEXPR_SYM_TARGET | QPOL_CEXPR_SYM_XTARGET)) {
+ case QPOL_CEXPR_SYM_USER:
+ {
+ if (qpol_iterator_create(policy, (void *)cns,
+ cexpr_name_state_get_cur_user, cexpr_name_state_next,
+ cexpr_name_state_end, cexpr_name_state_size, free, iter)) {
+ return STATUS_ERR;
+ }
+ break;
+ }
+ case QPOL_CEXPR_SYM_ROLE:
+ {
+ if (qpol_iterator_create(policy, (void *)cns,
+ cexpr_name_state_get_cur_role, cexpr_name_state_next,
+ cexpr_name_state_end, cexpr_name_state_size, free, iter)) {
+ return STATUS_ERR;
+ }
+ break;
+ }
+ case QPOL_CEXPR_SYM_TYPE:
+ {
+ if (qpol_iterator_create(policy, (void *)cns,
+ cexpr_name_state_get_cur_type, cexpr_name_state_next,
+ cexpr_name_state_end, cexpr_name_state_size, free, iter)) {
+ return STATUS_ERR;
+ }
+ break;
+ }
+ default:
+ {
+ ERR(policy, "%s", strerror(EINVAL));
+ free(cns);
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+ }
+
+ if (cns->inc->node && !ebitmap_get_bit(cns->inc, cns->cur))
+ qpol_iterator_next(*iter);
+
+ return STATUS_SUCCESS;
+}
+
+typedef struct class_constr_state
+{
+ constraint_node_t *head;
+ constraint_node_t *cur;
+ const qpol_class_t *obj_class;
+} class_constr_state_t;
+
+static int class_constr_state_end(const qpol_iterator_t * iter)
+{
+ class_constr_state_t *ccs = NULL;
+
+ if (!iter || !(ccs = (class_constr_state_t *) qpol_iterator_state(iter))) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ return ccs->cur ? 0 : 1;
+}
+
+static void *class_constr_state_get_cur(const qpol_iterator_t * iter)
+{
+ class_constr_state_t *ccs = NULL;
+ qpol_constraint_t *qc = NULL;
+
+ if (!iter || !(ccs = (class_constr_state_t *) qpol_iterator_state(iter)) || qpol_iterator_end(iter)) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ if (!(qc = calloc(1, sizeof(qpol_constraint_t)))) {
+ return NULL; /* errno set by calloc */
+ }
+ qc->obj_class = ccs->obj_class;
+ qc->constr = ccs->cur;
+
+ return qc;
+}
+
+static int class_constr_state_next(qpol_iterator_t * iter)
+{
+ class_constr_state_t *ccs = NULL;
+
+ if (!iter || !(ccs = (class_constr_state_t *) qpol_iterator_state(iter))) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ if (qpol_iterator_end(iter)) {
+ errno = ERANGE;
+ return STATUS_ERR;
+ }
+
+ ccs->cur = ccs->cur->next;
+
+ return STATUS_SUCCESS;
+}
+
+static size_t class_constr_state_size(const qpol_iterator_t * iter)
+{
+ class_constr_state_t *ccs = NULL;
+ constraint_node_t *tmp = NULL;
+ size_t count = 0;
+
+ if (!iter || !(ccs = (class_constr_state_t *) qpol_iterator_state(iter)) || qpol_iterator_end(iter)) {
+ errno = EINVAL;
+ return 0;
+ }
+
+ for (tmp = ccs->head; tmp; tmp = tmp->next)
+ count++;
+
+ return count;
+}
+
+int qpol_class_get_constraint_iter(const qpol_policy_t * policy, const qpol_class_t * obj_class, qpol_iterator_t ** constr)
+{
+ const policydb_t *db = NULL;
+ class_constr_state_t *ccs = NULL;
+ class_datum_t *internal_class = NULL;
+ int error = 0;
+
+ if (constr)
+ *constr = NULL;
+
+ if (!policy || !obj_class || !constr) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+ internal_class = (class_datum_t *) obj_class;
+
+ ccs = calloc(1, sizeof(class_constr_state_t));
+ if (!ccs) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ errno = error;
+ return STATUS_ERR;
+ }
+ ccs->obj_class = obj_class;
+ ccs->head = ccs->cur = internal_class->constraints;
+
+ if (qpol_iterator_create(policy, (void *)ccs, class_constr_state_get_cur,
+ class_constr_state_next, class_constr_state_end, class_constr_state_size, free, constr)) {
+ return STATUS_ERR;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_class_get_validatetrans_iter(const qpol_policy_t * policy, const qpol_class_t * obj_class, qpol_iterator_t ** vtrans)
+{
+ const policydb_t *db = NULL;
+ class_constr_state_t *ccs = NULL;
+ class_datum_t *internal_class = NULL;
+ int error = 0;
+
+ if (vtrans)
+ *vtrans = NULL;
+
+ if (!policy || !obj_class || !vtrans) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+ internal_class = (class_datum_t *) obj_class;
+
+ ccs = calloc(1, sizeof(class_constr_state_t));
+ if (!ccs) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ errno = error;
+ return STATUS_ERR;
+ }
+ ccs->obj_class = obj_class;
+ ccs->head = ccs->cur = internal_class->validatetrans;
+
+ if (qpol_iterator_create(policy, (void *)ccs, class_constr_state_get_cur,
+ class_constr_state_next, class_constr_state_end, class_constr_state_size, free, vtrans)) {
+ return STATUS_ERR;
+ }
+
+ return STATUS_SUCCESS;
+}
diff --git a/libqpol/src/context_query.c b/libqpol/src/context_query.c
new file mode 100644
index 0000000..cd17a21
--- /dev/null
+++ b/libqpol/src/context_query.c
@@ -0,0 +1,123 @@
+/**
+* @file
+* Defines the public interface for accessing contexts.
+*
+* @author Kevin Carr kcarr@tresys.com
+* @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
+*/
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <qpol/policy.h>
+#include <qpol/context_query.h>
+#include <qpol/user_query.h>
+#include <qpol/role_query.h>
+#include <qpol/type_query.h>
+#include <qpol/mls_query.h>
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/context.h>
+#include "qpol_internal.h"
+
+int qpol_context_get_user(const qpol_policy_t * policy, const qpol_context_t * context, const qpol_user_t ** user)
+{
+ policydb_t *db = NULL;
+ context_struct_t *internal_context = NULL;
+
+ if (user != NULL)
+ *user = NULL;
+
+ if (policy == NULL || context == NULL || user == NULL) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_context = (context_struct_t *) context;
+ db = &policy->p->p;
+
+ *user = (qpol_user_t *) db->user_val_to_struct[internal_context->user - 1];
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_context_get_role(const qpol_policy_t * policy, const qpol_context_t * context, const qpol_role_t ** role)
+{
+ policydb_t *db = NULL;
+ context_struct_t *internal_context = NULL;
+
+ if (role != NULL)
+ *role = NULL;
+
+ if (policy == NULL || context == NULL || role == NULL) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_context = (context_struct_t *) context;
+ db = &policy->p->p;
+
+ *role = (qpol_role_t *) db->role_val_to_struct[internal_context->role - 1];
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_context_get_type(const qpol_policy_t * policy, const qpol_context_t * context, const qpol_type_t ** type)
+{
+ policydb_t *db = NULL;
+ context_struct_t *internal_context = NULL;
+
+ if (type != NULL)
+ *type = NULL;
+
+ if (policy == NULL || context == NULL || type == NULL) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_context = (context_struct_t *) context;
+ db = &policy->p->p;
+
+ *type = (qpol_type_t *) db->type_val_to_struct[internal_context->type - 1];
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_context_get_range(const qpol_policy_t * policy, const qpol_context_t * context, const qpol_mls_range_t ** range)
+{
+ context_struct_t *internal_context = NULL;
+
+ if (range != NULL)
+ *range = NULL;
+
+ if (policy == NULL || context == NULL || range == NULL) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_context = (context_struct_t *) context;
+
+ *range = (qpol_mls_range_t *) & internal_context->range;
+
+ return STATUS_SUCCESS;
+}
diff --git a/libqpol/src/expand.c b/libqpol/src/expand.c
new file mode 100644
index 0000000..7aa5bdb
--- /dev/null
+++ b/libqpol/src/expand.c
@@ -0,0 +1,190 @@
+/**
+ * @file
+ *
+ * Provides a way for setools to expand policy.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2006-2008 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
+ */
+
+#include <config.h>
+
+#include <sepol/policydb/expand.h>
+#include <sepol/policydb.h>
+#include <stdlib.h>
+#include "qpol_internal.h"
+#include "expand.h"
+
+static int expand_type_attr_map(hashtab_key_t key __attribute__ ((unused)), hashtab_datum_t datum, void *ptr)
+{
+ type_datum_t *type = NULL, *orig_type;
+ policydb_t *db = (policydb_t *) ptr;
+ ebitmap_node_t *node = NULL;
+ uint32_t bit = 0;
+
+ type = (type_datum_t *) datum;
+ /* if this is an attribute go through its list
+ * of types and put in reverse mappings */
+ if (type->flavor == TYPE_ATTRIB) {
+ ebitmap_for_each_bit(&type->types, node, bit) {
+ if (ebitmap_node_get_bit(node, bit)) {
+ orig_type = db->type_val_to_struct[bit];
+ if (ebitmap_set_bit(&orig_type->types, type->s.value - 1, 1)) {
+ return -1;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+static int expand_type_permissive_map(hashtab_key_t key __attribute__ ((unused)), hashtab_datum_t datum, void *ptr)
+{
+#ifdef HAVE_SEPOL_PERMISSIVE_TYPES
+ type_datum_t *type = (type_datum_t *) datum;
+ policydb_t *db = (policydb_t *) ptr;
+
+ type = (type_datum_t *) datum;
+ /* if this type is marked as permissive, then set its
+ corresponding bit in the permissive map. note that unlike
+ other bitmaps, this one does not subtract 1 in the
+ bitmap. */
+ if (type->flags & TYPE_FLAGS_PERMISSIVE) {
+ uint32_t value;
+ if (type->flavor == TYPE_ALIAS) {
+ /* aliases that came from modules should use the value
+ * referenced to by that alias */
+ value = type->primary;
+ } else {
+ value = type->s.value;
+ }
+ if (ebitmap_set_bit(&db->permissive_map, value, 1)) {
+ return -1;
+ }
+ }
+#endif
+ return 0;
+}
+
+int qpol_expand_module(qpol_policy_t * base, int neverallows)
+{
+ unsigned int i;
+ uint32_t *typemap = NULL, *boolmap = NULL, *rolemap = NULL, *usermap = NULL;
+ policydb_t *db;
+ int rt, error = 0;
+
+ INFO(base, "%s", "Expanding policy. (Step 3 of 5)");
+ if (base == NULL) {
+ ERR(base, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return -1;
+ }
+ db = &base->p->p;
+
+ /* activate the global branch before expansion */
+ db->global->branch_list->enabled = 1;
+ db->global->enabled = db->global->branch_list;
+
+ /* expand out the types to include all the attributes */
+ if (hashtab_map(db->p_types.table, expand_type_attr_map, (db))) {
+ error = errno;
+ ERR(base, "%s", "Error expanding attributes for types.");
+ goto err;
+ }
+#ifdef HAVE_SEPOL_PERMISSIVE_TYPES
+ /* fill in the permissive types bitmap. this is normally done
+ * in type_copy_callback(), but types are not copied in
+ * expand_module_avrules() */
+ if (hashtab_map(db->p_types.table, expand_type_permissive_map, (db))) {
+ error = errno;
+ ERR(base, "%s", "Error expanding attributes for types.");
+ goto err;
+ }
+#endif
+
+ /* Build the typemap such that we can expand into the same policy */
+ typemap = (uint32_t *) calloc(db->p_types.nprim, sizeof(uint32_t));
+ if (typemap == NULL) {
+ error = errno;
+ ERR(base, "%s", strerror(errno));
+ goto err;
+ }
+ for (i = 0; i < db->p_types.nprim; i++) {
+ typemap[i] = i + 1;
+ }
+
+#ifdef HAVE_SEPOL_BOOLMAP
+ boolmap = (uint32_t *) calloc(db->p_bools.nprim, sizeof(uint32_t));
+ if (boolmap == NULL) {
+ error = errno;
+ ERR(base, "%s", strerror(errno));
+ goto err;
+ }
+ for (i = 0; i < db->p_bools.nprim; i++) {
+ boolmap[i] = i + 1;
+ }
+
+#ifdef HAVE_SEPOL_USER_ROLE_MAPPING
+ rolemap = (uint32_t *) calloc(db->p_roles.nprim, sizeof(uint32_t));
+ if (rolemap == NULL) {
+ error = errno;
+ ERR(base, "%s", strerror(errno));
+ goto err;
+ }
+ for (i = 0; i < db->p_roles.nprim; i++) {
+ rolemap[i] = i + 1;
+ }
+ usermap = (uint32_t *) calloc(db->p_users.nprim, sizeof(uint32_t));
+ if (usermap == NULL) {
+ error = errno;
+ ERR(base, "%s", strerror(errno));
+ goto err;
+ }
+ for (i = 0; i < db->p_users.nprim; i++) {
+ usermap[i] = i + 1;
+ }
+ rt = expand_module_avrules(base->sh, db, db, typemap, boolmap, rolemap, usermap, 0, neverallows);
+#else
+ rt = expand_module_avrules(base->sh, db, db, typemap, boolmap, 0, neverallows);
+#endif // end of user/role mapping
+
+#else
+ rt = expand_module_avrules(base->sh, db, db, typemap, 0, neverallows);
+#endif // end of boolean mapping
+ if (rt < 0) {
+ error = errno;
+ goto err;
+ }
+ rt = 0;
+
+ exit:
+ free(typemap);
+ free(boolmap);
+ free(rolemap);
+ free(usermap);
+ errno = error;
+ return rt;
+ err:
+ rt = -1;
+ /* libsepol does not always set errno correctly, so have a
+ default errno here */
+ if (!error)
+ error = EIO;
+ goto exit;
+}
diff --git a/libqpol/src/expand.h b/libqpol/src/expand.h
new file mode 100644
index 0000000..7f400d4
--- /dev/null
+++ b/libqpol/src/expand.h
@@ -0,0 +1,51 @@
+/**
+ * @file
+ *
+ * Public interface for expanding a modular policy.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @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
+ */
+
+#ifndef QPOL_EXPAND_H
+#define QPOL_EXPAND_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <qpol/policy.h>
+
+/**
+ * Expand a policy. Linking should always be done prior to calling
+ * this function.
+ *
+ * @param base the module to expand.
+ * @param neverallows if non-zero expand neverallows.
+ * @return 0 on success, -1 on error.
+ */
+ int qpol_expand_module(qpol_policy_t * base, int neverallows);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libqpol/src/fs_use_query.c b/libqpol/src/fs_use_query.c
new file mode 100644
index 0000000..c6fca82
--- /dev/null
+++ b/libqpol/src/fs_use_query.c
@@ -0,0 +1,167 @@
+/**
+* @file
+* Defines the public interface for searching and iterating over fs_use statements.
+*
+* @author Kevin Carr kcarr@tresys.com
+* @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
+*/
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <qpol/iterator.h>
+#include <qpol/policy.h>
+#include <qpol/fs_use_query.h>
+#include <qpol/context_query.h>
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/context.h>
+#include "qpol_internal.h"
+#include "iterator_internal.h"
+
+int qpol_policy_get_fs_use_by_name(const qpol_policy_t * policy, const char *name, const qpol_fs_use_t ** ocon)
+{
+ ocontext_t *tmp = NULL;
+ policydb_t *db = NULL;
+
+ if (ocon != NULL)
+ *ocon = NULL;
+
+ if (policy == NULL || name == NULL || ocon == NULL) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+ for (tmp = db->ocontexts[OCON_FSUSE]; tmp; tmp = tmp->next) {
+ if (!strcmp(name, tmp->u.name))
+ break;
+ }
+
+ *ocon = (qpol_fs_use_t *) tmp;
+
+ if (*ocon == NULL) {
+ ERR(policy, "could not find fs_use statement for %s", name);
+ errno = ENOENT;
+ return STATUS_ERR;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_policy_get_fs_use_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter)
+{
+ policydb_t *db = NULL;
+ int error = 0;
+ ocon_state_t *os = NULL;
+
+ if (iter != NULL)
+ *iter = NULL;
+
+ if (policy == NULL || iter == NULL) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+
+ os = calloc(1, sizeof(ocon_state_t));
+ if (os == NULL) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = error;
+ return STATUS_ERR;
+ }
+
+ os->head = os->cur = db->ocontexts[OCON_FSUSE];
+
+ if (qpol_iterator_create(policy, (void *)os, ocon_state_get_cur,
+ ocon_state_next, ocon_state_end, ocon_state_size, free, iter)) {
+ free(os);
+ return STATUS_ERR;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_fs_use_get_name(const qpol_policy_t * policy, const qpol_fs_use_t * ocon, const char **name)
+{
+ ocontext_t *internal_ocon = NULL;
+
+ if (name != NULL)
+ *name = NULL;
+
+ if (policy == NULL || ocon == NULL || name == NULL) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_ocon = (ocontext_t *) ocon;
+ *name = internal_ocon->u.name;
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_fs_use_get_behavior(const qpol_policy_t * policy, const qpol_fs_use_t * ocon, uint32_t * behavior)
+{
+ ocontext_t *internal_ocon = NULL;
+
+ if (behavior != NULL)
+ *behavior = 0;
+
+ if (policy == NULL || ocon == NULL || behavior == NULL) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_ocon = (ocontext_t *) ocon;
+ *behavior = internal_ocon->v.behavior;
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_fs_use_get_context(const qpol_policy_t * policy, const qpol_fs_use_t * ocon, const qpol_context_t ** context)
+{
+ ocontext_t *internal_ocon = NULL;
+
+ if (context != NULL)
+ *context = NULL;
+
+ if (policy == NULL || ocon == NULL || context == NULL) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_ocon = (ocontext_t *) ocon;
+
+ if (internal_ocon->v.behavior == QPOL_FS_USE_PSID) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ *context = (qpol_context_t *) & (internal_ocon->context[0]);
+
+ return STATUS_SUCCESS;
+}
diff --git a/libqpol/src/genfscon_query.c b/libqpol/src/genfscon_query.c
new file mode 100644
index 0000000..e226f2a
--- /dev/null
+++ b/libqpol/src/genfscon_query.c
@@ -0,0 +1,294 @@
+/**
+* @file
+* Defines the public interface for searching and iterating over genfscon statements.
+*
+* @author Kevin Carr kcarr@tresys.com
+* @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
+*/
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <qpol/iterator.h>
+#include <qpol/policy.h>
+#include <qpol/context_query.h>
+#include <qpol/genfscon_query.h>
+#include <sepol/policydb/policydb.h>
+#include "qpol_internal.h"
+#include "iterator_internal.h"
+
+struct qpol_genfscon
+{
+ const char *fs_name;
+ const char *path;
+ const context_struct_t *context;
+ uint32_t sclass;
+};
+
+int qpol_policy_get_genfscon_by_name(const qpol_policy_t * policy, const char *name, const char *path, qpol_genfscon_t ** genfscon)
+{
+ genfs_t *tmp = NULL;
+ ocontext_t *tmp2 = NULL;
+ policydb_t *db = NULL;
+ int error = 0;
+
+ if (genfscon != NULL)
+ *genfscon = NULL;
+
+ if (policy == NULL || name == NULL || path == NULL || genfscon == NULL) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+ for (tmp = db->genfs; tmp; tmp = tmp->next) {
+ if (!strcmp(name, tmp->fstype))
+ break;
+ }
+
+ if (tmp) {
+ for (tmp2 = tmp->head; tmp2; tmp2 = tmp2->next) {
+ if (!strcmp(path, tmp2->u.name))
+ break;
+ }
+ }
+
+ if (tmp && tmp2) {
+ *genfscon = calloc(1, sizeof(qpol_genfscon_t));
+ if (!(*genfscon)) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = errno;
+ return STATUS_ERR;
+ }
+ /* shallow copy only the struct pointer (genfscon) should be free()'ed */
+ (*genfscon)->fs_name = tmp->fstype;
+ (*genfscon)->path = tmp2->u.name;
+ (*genfscon)->context = &(tmp2->context[0]);
+ (*genfscon)->sclass = tmp2->v.sclass;
+ }
+
+ if (*genfscon == NULL) {
+ ERR(policy, "could not find genfscon statement for %s %s", name, path);
+ errno = ENOENT;
+ return STATUS_ERR;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+typedef struct genfs_state
+{
+ genfs_t *head;
+ genfs_t *cur;
+ ocontext_t *cur_path;
+} genfs_state_t;
+
+static int genfs_state_end(const qpol_iterator_t * iter)
+{
+ genfs_state_t *gs = NULL;
+
+ if (iter == NULL || qpol_iterator_state(iter) == NULL) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ gs = (genfs_state_t *) qpol_iterator_state(iter);
+
+ if (gs->cur == NULL && gs->cur_path == NULL)
+ return 1;
+
+ return 0;
+}
+
+static void *genfs_state_get_cur(const qpol_iterator_t * iter)
+{
+ genfs_state_t *gs = NULL;
+ qpol_genfscon_t *genfscon = NULL;
+
+ if (iter == NULL || qpol_iterator_state(iter) == NULL || genfs_state_end(iter)) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ gs = (genfs_state_t *) qpol_iterator_state(iter);
+
+ genfscon = calloc(1, sizeof(qpol_genfscon_t));
+ if (!genfscon) {
+ return NULL;
+ }
+
+ genfscon->fs_name = gs->cur->fstype;
+ genfscon->path = gs->cur_path->u.name;
+ genfscon->context = &(gs->cur_path->context[0]);
+ genfscon->sclass = gs->cur_path->v.sclass;
+
+ return genfscon;
+}
+
+static size_t genfs_state_size(const qpol_iterator_t * iter)
+{
+ genfs_state_t *gs = NULL;
+ size_t count = 0;
+ genfs_t *genfs = NULL;
+ ocontext_t *path = NULL;
+
+ if (iter == NULL || qpol_iterator_state(iter) == NULL) {
+ errno = EINVAL;
+ return 0;
+ }
+
+ gs = (genfs_state_t *) qpol_iterator_state(iter);
+
+ for (genfs = gs->head; genfs; genfs = genfs->next)
+ for (path = genfs->head; path; path = path->next)
+ count++;
+
+ return count;
+}
+
+static int genfs_state_next(qpol_iterator_t * iter)
+{
+ genfs_state_t *gs = NULL;
+
+ if (iter == NULL || qpol_iterator_state(iter) == NULL) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ gs = (genfs_state_t *) qpol_iterator_state(iter);
+
+ if (gs->cur == NULL) {
+ errno = ERANGE;
+ return STATUS_ERR;
+ }
+
+ if (gs->cur_path->next != NULL) {
+ gs->cur_path = gs->cur_path->next;
+ } else {
+ gs->cur = gs->cur->next;
+ gs->cur_path = gs->cur ? gs->cur->head : NULL;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_policy_get_genfscon_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter)
+{
+ policydb_t *db = NULL;
+ genfs_state_t *gs = NULL;
+ int error = 0;
+
+ if (iter != NULL)
+ *iter = NULL;
+
+ if (policy == NULL || iter == NULL) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+
+ gs = calloc(1, sizeof(genfs_state_t));
+ if (gs == NULL) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = error;
+ return STATUS_ERR;
+ }
+
+ gs->head = gs->cur = db->genfs;
+ if (gs->head)
+ gs->cur_path = gs->head->head;
+
+ if (qpol_iterator_create(policy, (void *)gs, genfs_state_get_cur,
+ genfs_state_next, genfs_state_end, genfs_state_size, free, iter)) {
+ free(gs);
+ return STATUS_ERR;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_genfscon_get_name(const qpol_policy_t * policy, const qpol_genfscon_t * genfs, const char **name)
+{
+ if (name != NULL)
+ *name = NULL;
+
+ if (policy == NULL || genfs == NULL || name == NULL) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ *name = genfs->fs_name;
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_genfscon_get_path(const qpol_policy_t * policy, const qpol_genfscon_t * genfs, const char **path)
+{
+ if (path != NULL)
+ *path = NULL;
+
+ if (policy == NULL || genfs == NULL || path == NULL) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ *path = genfs->path;
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_genfscon_get_class(const qpol_policy_t * policy, const qpol_genfscon_t * genfs, uint32_t * obj_class)
+{
+ if (obj_class != NULL)
+ *obj_class = 0;
+
+ if (policy == NULL || genfs == NULL || obj_class == NULL) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ *obj_class = genfs->sclass;
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_genfscon_get_context(const qpol_policy_t * policy, const qpol_genfscon_t * genfscon, const qpol_context_t ** context)
+{
+ if (context != NULL)
+ *context = NULL;
+
+ if (policy == NULL || genfscon == NULL || context == NULL) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ *context = (qpol_context_t *) genfscon->context;
+
+ return STATUS_SUCCESS;
+}
diff --git a/libqpol/src/isid_query.c b/libqpol/src/isid_query.c
new file mode 100644
index 0000000..8d7546e
--- /dev/null
+++ b/libqpol/src/isid_query.c
@@ -0,0 +1,139 @@
+/**
+* @file
+* Defines the public interface for searching and iterating over initial SIDs.
+*
+* @author Kevin Carr kcarr@tresys.com
+* @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
+*/
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <qpol/iterator.h>
+#include <qpol/policy.h>
+#include <qpol/context_query.h>
+#include <qpol/isid_query.h>
+#include <sepol/policydb/policydb.h>
+#include "qpol_internal.h"
+#include "iterator_internal.h"
+
+int qpol_policy_get_isid_by_name(const qpol_policy_t * policy, const char *name, const qpol_isid_t ** ocon)
+{
+ ocontext_t *tmp = NULL;
+ policydb_t *db = NULL;
+
+ if (ocon != NULL)
+ *ocon = NULL;
+
+ if (policy == NULL || name == NULL || ocon == NULL) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+ for (tmp = db->ocontexts[OCON_ISID]; tmp; tmp = tmp->next) {
+ if (!strcmp(name, tmp->u.name))
+ break;
+ }
+
+ *ocon = (qpol_isid_t *) tmp;
+
+ if (*ocon == NULL) {
+ ERR(policy, "could not find initial SID statement for %s", name);
+ errno = ENOENT;
+ return STATUS_ERR;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_policy_get_isid_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter)
+{
+ policydb_t *db = NULL;
+ ocon_state_t *os = NULL;
+ int error = 0;
+
+ if (iter != NULL)
+ *iter = NULL;
+
+ if (policy == NULL || iter == NULL) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+
+ os = calloc(1, sizeof(ocon_state_t));
+ if (os == NULL) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = error;
+ return STATUS_ERR;
+ }
+
+ os->head = os->cur = db->ocontexts[OCON_ISID];
+
+ if (qpol_iterator_create(policy, (void *)os, ocon_state_get_cur,
+ ocon_state_next, ocon_state_end, ocon_state_size, free, iter)) {
+ free(os);
+ return STATUS_ERR;
+ }
+ return STATUS_SUCCESS;
+}
+
+int qpol_isid_get_name(const qpol_policy_t * policy, const qpol_isid_t * ocon, const char **name)
+{
+ ocontext_t *internal_ocon = NULL;
+
+ if (name != NULL)
+ *name = NULL;
+
+ if (policy == NULL || ocon == NULL || name == NULL) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_ocon = (ocontext_t *) ocon;
+ *name = internal_ocon->u.name;
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_isid_get_context(const qpol_policy_t * policy, const qpol_isid_t * ocon, const qpol_context_t ** context)
+{
+ ocontext_t *internal_ocon = NULL;
+
+ if (context != NULL)
+ *context = NULL;
+
+ if (policy == NULL || ocon == NULL || context == NULL) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_ocon = (ocontext_t *) ocon;
+ *context = (qpol_context_t *) & (internal_ocon->context[0]);
+
+ return STATUS_SUCCESS;
+}
diff --git a/libqpol/src/iterator.c b/libqpol/src/iterator.c
new file mode 100644
index 0000000..ffc5f7a
--- /dev/null
+++ b/libqpol/src/iterator.c
@@ -0,0 +1,797 @@
+/**
+ * @file
+ * Contains the implementation of the qpol_iterator API, both
+ * public and private, for returning lists of components and rules
+ * from the policy database.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2006-2008 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
+ */
+
+#include <config.h>
+
+#include <qpol/iterator.h>
+#include <qpol/policy.h>
+#include <qpol/mls_query.h>
+
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/polcaps.h>
+#include <sepol/policydb/util.h>
+#include <sepol/policydb.h>
+
+#include "qpol_internal.h"
+#include "iterator_internal.h"
+
+/**
+ * Declaration of qpol_iterator, an arbitrary valued policy component
+ * iterator used to return lists of components.
+ *
+ */
+struct qpol_iterator
+{
+ policydb_t *policy;
+ void *state;
+ void *(*get_cur) (const qpol_iterator_t * iter);
+ int (*next) (qpol_iterator_t * iter);
+ int (*end) (const qpol_iterator_t * iter);
+ size_t(*size) (const qpol_iterator_t * iter);
+ void (*free_fn) (void *x);
+};
+
+/**
+ * The number of buckets in sepol's av tables was statically set in
+ * libsepol < 2.0.20. With libsepol 2.0.20, this size was dynamically
+ * calculated based upon the number of rules.
+ */
+static uint32_t iterator_get_avtab_size(const avtab_t * avtab)
+{
+#ifdef SEPOL_DYNAMIC_AVTAB
+ return avtab->nslot;
+#else
+ return AVTAB_SIZE;
+#endif
+}
+
+int qpol_iterator_create(const qpol_policy_t * policy, void *state,
+ void *(*get_cur) (const qpol_iterator_t * iter),
+ int (*next) (qpol_iterator_t * iter),
+ int (*end) (const qpol_iterator_t * iter),
+ size_t(*size) (const qpol_iterator_t * iter), void (*free_fn) (void *x), qpol_iterator_t ** iter)
+{
+ int error = 0;
+
+ if (iter != NULL)
+ *iter = NULL;
+
+ if (policy == NULL || state == NULL || iter == NULL || get_cur == NULL || next == NULL || end == NULL || size == NULL) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ *iter = calloc(1, sizeof(struct qpol_iterator));
+ if (*iter == NULL) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = error;
+ return STATUS_ERR;
+ }
+
+ (*iter)->policy = &policy->p->p;
+ (*iter)->state = state;
+ (*iter)->get_cur = get_cur;
+ (*iter)->next = next;
+ (*iter)->end = end;
+ (*iter)->size = size;
+ (*iter)->free_fn = free_fn;
+
+ return STATUS_SUCCESS;
+}
+
+void *qpol_iterator_state(const qpol_iterator_t * iter)
+{
+ if (iter == NULL || iter->state == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ return iter->state;
+}
+
+const policydb_t *qpol_iterator_policy(const qpol_iterator_t * iter)
+{
+ if (iter == NULL || iter->policy == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ return iter->policy;
+}
+
+void *hash_state_get_cur(const qpol_iterator_t * iter)
+{
+ hash_state_t *hs = NULL;
+
+ if (iter == NULL || iter->state == NULL || hash_state_end(iter)) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ hs = (hash_state_t *) iter->state;
+
+ return hs->node->datum;
+}
+
+void *hash_state_get_cur_key(const qpol_iterator_t * iter)
+{
+ hash_state_t *hs = NULL;
+
+ if (iter == NULL || iter->state == NULL || hash_state_end(iter)) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ hs = (hash_state_t *) iter->state;
+
+ return hs->node->key;
+}
+
+void *ocon_state_get_cur(const qpol_iterator_t * iter)
+{
+ ocon_state_t *os = NULL;
+
+ if (iter == NULL || iter->state == NULL || ocon_state_end(iter)) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ os = (ocon_state_t *) iter->state;
+
+ return os->cur;
+}
+
+void *avtab_state_get_cur(const qpol_iterator_t * iter)
+{
+ avtab_state_t *state;
+
+ if (iter == NULL || iter->state == NULL || avtab_state_end(iter)) {
+ errno = EINVAL;
+ return NULL;
+ }
+ state = (avtab_state_t *) iter->state;
+ return state->node;
+}
+
+int hash_state_next(qpol_iterator_t * iter)
+{
+ hash_state_t *hs = NULL;
+
+ if (iter == NULL || iter->state == NULL) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ hs = (hash_state_t *) iter->state;
+
+ if (hs->table == NULL || *(hs->table) == NULL || hs->bucket >= (*(hs->table))->size) {
+ errno = ERANGE;
+ return STATUS_ERR;
+ }
+
+ if (hs->node != NULL && hs->node->next != NULL) {
+ hs->node = hs->node->next;
+ } else {
+ do {
+ hs->bucket++;
+ if (hs->bucket < (*(hs->table))->size) {
+ hs->node = (*(hs->table))->htable[hs->bucket];
+ } else {
+ hs->node = NULL;
+ }
+ } while (hs->bucket < (*(hs->table))->size && hs->node == NULL);
+ }
+
+ return STATUS_SUCCESS;
+}
+
+int ebitmap_state_next(qpol_iterator_t * iter)
+{
+ ebitmap_state_t *es = NULL;
+
+ if (iter == NULL || iter->state == NULL) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ es = (ebitmap_state_t *) iter->state;
+
+ if (es->cur >= es->bmap->highbit) {
+ errno = ERANGE;
+ return STATUS_ERR;
+ }
+
+ do {
+ es->cur++;
+ } while (es->cur < es->bmap->highbit && !ebitmap_get_bit(es->bmap, es->cur));
+
+ return STATUS_SUCCESS;
+}
+
+int ocon_state_next(qpol_iterator_t * iter)
+{
+ ocon_state_t *os = NULL;
+
+ if (iter == NULL || iter->state == NULL) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ os = (ocon_state_t *) iter->state;
+
+ if (os->cur == NULL) {
+ errno = ERANGE;
+ return STATUS_ERR;
+ }
+
+ os->cur = os->cur->next;
+
+ return STATUS_SUCCESS;
+}
+
+int avtab_state_next(qpol_iterator_t * iter)
+{
+ avtab_t *avtab;
+ avtab_state_t *state;
+
+ if (iter == NULL || iter->state == NULL) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ state = iter->state;
+ avtab = (state->which == QPOL_AVTAB_STATE_AV ? state->ucond_tab : state->cond_tab);
+
+ if ((!avtab->htable || state->bucket >= iterator_get_avtab_size(avtab)) && state->which == QPOL_AVTAB_STATE_COND) {
+ errno = ERANGE;
+ return STATUS_ERR;
+ }
+
+ do {
+ if (state->node != NULL && state->node->next != NULL) {
+ state->node = state->node->next;
+ } else {
+ /* find the next bucket */
+ do {
+ state->bucket++;
+ if (!avtab->htable || state->bucket >= iterator_get_avtab_size(avtab)) {
+ if (state->which == QPOL_AVTAB_STATE_AV) {
+ state->bucket = 0;
+ avtab = state->cond_tab;
+ state->which = QPOL_AVTAB_STATE_COND;
+ } else {
+ state->node = NULL;
+ break;
+ }
+ }
+ if (avtab->htable && avtab->htable[state->bucket] != NULL) {
+ state->node = avtab->htable[state->bucket];
+ break;
+ }
+ } while (avtab->htable && state->bucket < iterator_get_avtab_size(avtab));
+ }
+ } while (avtab->htable && state->bucket < iterator_get_avtab_size(avtab) &&
+ state->node ? !(state->rule_type_mask & state->node->key.specified) : 0);
+
+ return STATUS_SUCCESS;
+}
+
+int hash_state_end(const qpol_iterator_t * iter)
+{
+ hash_state_t *hs = NULL;
+
+ if (iter == NULL || iter->state == NULL) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ hs = (hash_state_t *) iter->state;
+
+ if (hs->table == NULL || *(hs->table) == NULL || (*(hs->table))->nel == 0 || hs->bucket >= (*(hs->table))->size)
+ return 1;
+
+ return 0;
+}
+
+int ebitmap_state_end(const qpol_iterator_t * iter)
+{
+ ebitmap_state_t *es = NULL;
+
+ if (iter == NULL || iter->state == NULL) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ es = (ebitmap_state_t *) iter->state;
+
+ if (es->cur >= es->bmap->highbit)
+ return 1;
+
+ return 0;
+}
+
+int ocon_state_end(const qpol_iterator_t * iter)
+{
+ ocon_state_t *os = NULL;
+
+ if (iter == NULL || iter->state == NULL) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ os = (ocon_state_t *) iter->state;
+
+ if (os->cur == NULL)
+ return 1;
+
+ return 0;
+}
+
+int avtab_state_end(const qpol_iterator_t * iter)
+{
+ avtab_state_t *state;
+ avtab_t *avtab;
+
+ if (iter == NULL || iter->state == NULL) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+ state = iter->state;
+ avtab = (state->which == QPOL_AVTAB_STATE_AV ? state->ucond_tab : state->cond_tab);
+ if ((!avtab->htable || state->bucket >= iterator_get_avtab_size(avtab)) && state->which == QPOL_AVTAB_STATE_COND)
+ return 1;
+ return 0;
+}
+
+size_t hash_state_size(const qpol_iterator_t * iter)
+{
+ hash_state_t *hs = NULL;
+
+ if (iter == NULL || iter->state == NULL) {
+ errno = EINVAL;
+ return 0;
+ }
+
+ hs = (hash_state_t *) iter->state;
+
+ return (*(hs->table))->nel;
+}
+
+size_t ebitmap_state_size(const qpol_iterator_t * iter)
+{
+ ebitmap_state_t *es = NULL;
+ size_t count = 0, bit = 0;
+ ebitmap_node_t *node = NULL;
+
+ if (iter == NULL || iter->state == NULL) {
+ errno = EINVAL;
+ return 0;
+ }
+
+ es = (ebitmap_state_t *) iter->state;
+
+ ebitmap_for_each_bit(es->bmap, node, bit) {
+ count += ebitmap_get_bit(es->bmap, bit);
+ }
+
+ return count;
+}
+
+size_t ocon_state_size(const qpol_iterator_t * iter)
+{
+ ocon_state_t *os = NULL;
+ size_t count = 0;
+ ocontext_t *ocon = NULL;
+
+ if (iter == NULL || iter->state == NULL) {
+ errno = EINVAL;
+ return 0;
+ }
+
+ os = (ocon_state_t *) iter->state;
+
+ for (ocon = os->head; ocon; ocon = ocon->next)
+ count++;
+
+ return count;
+}
+
+size_t avtab_state_size(const qpol_iterator_t * iter)
+{
+ avtab_state_t *state;
+ avtab_t *avtab;
+ size_t count = 0;
+ avtab_ptr_t node = NULL;
+ uint32_t bucket = 0;
+
+ if (iter == NULL || iter->state == NULL || iter->policy == NULL) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ state = iter->state;
+ avtab = state->ucond_tab;
+
+ for (bucket = 0; avtab->htable && bucket < iterator_get_avtab_size(avtab); bucket++) {
+ for (node = avtab->htable[bucket]; node; node = node->next) {
+ if (node->key.specified & state->rule_type_mask)
+ count++;
+ }
+ }
+
+ avtab = state->cond_tab;
+
+ for (bucket = 0; avtab->htable && bucket < iterator_get_avtab_size(avtab); bucket++) {
+ for (node = avtab->htable[bucket]; node; node = node->next) {
+ if (node->key.specified & state->rule_type_mask)
+ count++;
+ }
+ }
+
+ return count;
+}
+
+void qpol_iterator_destroy(qpol_iterator_t ** iter)
+{
+ if (iter == NULL || *iter == NULL)
+ return;
+
+ if ((*iter)->free_fn)
+ (*iter)->free_fn((*iter)->state);
+
+ free(*iter);
+ *iter = NULL;
+}
+
+int qpol_iterator_get_item(const qpol_iterator_t * iter, void **item)
+{
+ if (item != NULL)
+ *item = NULL;
+
+ if (iter == NULL || iter->get_cur == NULL || item == NULL) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ *item = iter->get_cur(iter);
+ if (*item == NULL)
+ return STATUS_ERR;
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_iterator_next(qpol_iterator_t * iter)
+{
+ if (iter == NULL || iter->next == NULL) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ return iter->next(iter);
+}
+
+int qpol_iterator_end(const qpol_iterator_t * iter)
+{
+ if (iter == NULL || iter->end == NULL) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ return iter->end(iter);
+}
+
+int qpol_iterator_get_size(const qpol_iterator_t * iter, size_t * size)
+{
+ if (size != NULL)
+ *size = 0;
+
+ if (iter == NULL || size == NULL || iter->size == NULL) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ *size = iter->size(iter);
+
+ return STATUS_SUCCESS;
+}
+
+void *ebitmap_state_get_cur_type(const qpol_iterator_t * iter)
+{
+ ebitmap_state_t *es = NULL;
+ const policydb_t *db = NULL;
+
+ if (iter == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ es = qpol_iterator_state(iter);
+ if (es == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ db = qpol_iterator_policy(iter);
+ if (db == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ return db->type_val_to_struct[es->cur];
+}
+
+void *ebitmap_state_get_cur_role(const qpol_iterator_t * iter)
+{
+ ebitmap_state_t *es = NULL;
+ const policydb_t *db = NULL;
+
+ if (iter == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ es = qpol_iterator_state(iter);
+ if (es == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ db = qpol_iterator_policy(iter);
+ if (db == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ return db->role_val_to_struct[es->cur];
+}
+
+void *ebitmap_state_get_cur_cat(const qpol_iterator_t * iter)
+{
+ ebitmap_state_t *es = NULL;
+ const policydb_t *db = NULL;
+ const qpol_cat_t *cat = NULL;
+ sepol_policydb_t sp;
+ qpol_policy_t qp;
+
+ if (iter == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ es = qpol_iterator_state(iter);
+ if (es == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ db = qpol_iterator_policy(iter);
+ if (db == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ /* shallow copy is safe here */
+ sp.p = *db;
+ qp.p = &sp;
+ qp.fn = NULL;
+
+ qpol_policy_get_cat_by_name(&qp, db->p_cat_val_to_name[es->cur], &cat);
+
+ /* There is no val_to_struct for categories; this requires that qpol
+ * search for the struct, but it can't be returned as const here so
+ * cast it to void* explicitly. */
+ return (void *)cat;
+}
+
+void *ebitmap_state_get_cur_permissive(const qpol_iterator_t * iter)
+{
+ ebitmap_state_t *es = NULL;
+ const policydb_t *db = NULL;
+
+ if (iter == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ es = qpol_iterator_state(iter);
+ if (es == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ db = qpol_iterator_policy(iter);
+ if (db == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ return db->type_val_to_struct[es->cur - 1];
+}
+
+void *ebitmap_state_get_cur_polcap(const qpol_iterator_t * iter)
+{
+ ebitmap_state_t *es = NULL;
+ const policydb_t *db = NULL;
+
+ if (iter == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ es = qpol_iterator_state(iter);
+ if (es == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ db = qpol_iterator_policy(iter);
+ if (db == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ return sepol_polcap_getname(es->cur);
+}
+
+void ebitmap_state_destroy(void *es)
+{
+ ebitmap_state_t *ies = (ebitmap_state_t *) es;
+
+ if (!es)
+ return;
+
+ ebitmap_destroy(ies->bmap);
+ free(ies->bmap);
+ free(ies);
+}
+
+int perm_state_end(const qpol_iterator_t * iter)
+{
+ perm_state_t *ps = NULL;
+ const policydb_t *db = NULL;
+ unsigned int perm_max = 0;
+
+ if (iter == NULL || (ps = qpol_iterator_state(iter)) == NULL || (db = qpol_iterator_policy(iter)) == NULL) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ /* permission max is number of permissions in the class which includes
+ * the number of permissions in its common if it inherits one */
+ perm_max = db->class_val_to_struct[ps->obj_class_val - 1]->permissions.nprim;
+ if (perm_max > 32) {
+ errno = EDOM; /* perms set mask is a uint32_t cannot use more than 32 bits */
+ return STATUS_ERR;
+ }
+
+ if (!(ps->perm_set) || ps->cur >= perm_max)
+ return 1;
+
+ return 0;
+}
+
+void *perm_state_get_cur(const qpol_iterator_t * iter)
+{
+ const policydb_t *db = NULL;
+ class_datum_t *obj_class = NULL;
+ common_datum_t *comm = NULL;
+ perm_state_t *ps = NULL;
+ unsigned int perm_max = 0;
+ char *tmp = NULL;
+
+ if (iter == NULL || (db = qpol_iterator_policy(iter)) == NULL ||
+ (ps = (perm_state_t *) qpol_iterator_state(iter)) == NULL || perm_state_end(iter)) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ obj_class = db->class_val_to_struct[ps->obj_class_val - 1];
+ comm = obj_class->comdatum;
+
+ /* permission max is number of permissions in the class which includes
+ * the number of permissions in its common if it inherits one */
+ perm_max = obj_class->permissions.nprim;
+ if (perm_max > 32) {
+ errno = EDOM; /* perms set mask is a uint32_t cannot use more than 32 bits */
+ return NULL;
+ }
+ if (ps->cur >= perm_max) {
+ errno = ERANGE;
+ return NULL;
+ }
+ if (!(ps->perm_set & 1 << (ps->cur))) { /* perm bit not set? */
+ errno = EINVAL;
+ return NULL;
+ }
+
+ /* explicit const_cast for sepol */
+ tmp = sepol_av_to_string((policydb_t *) db, ps->obj_class_val, (sepol_access_vector_t) 1 << (ps->cur));
+ if (tmp) {
+ tmp++; /*sepol_av_to_string prepends a ' ' to the name */
+ return strdup(tmp);
+ } else {
+ errno = EINVAL;
+ return NULL;
+ }
+}
+
+int perm_state_next(qpol_iterator_t * iter)
+{
+ perm_state_t *ps = NULL;
+ const policydb_t *db = NULL;
+ unsigned int perm_max = 0;
+
+ if (iter == NULL || (ps = qpol_iterator_state(iter)) == NULL ||
+ (db = qpol_iterator_policy(iter)) == NULL || perm_state_end(iter)) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ /* permission max is number of permissions in the class which includes
+ * the number of permissions in its common if it inherits one */
+ perm_max = db->class_val_to_struct[ps->obj_class_val - 1]->permissions.nprim;
+ if (perm_max > 32) {
+ errno = EDOM; /* perms set mask is a uint32_t cannot use more than 32 bits */
+ return STATUS_ERR;
+ }
+
+ if (ps->cur >= perm_max) {
+ errno = ERANGE;
+ return STATUS_ERR;
+ }
+
+ do {
+ ps->cur++;
+ } while (ps->cur < perm_max && !(ps->perm_set & 1 << (ps->cur)));
+
+ return STATUS_SUCCESS;
+}
+
+size_t perm_state_size(const qpol_iterator_t * iter)
+{
+ perm_state_t *ps = NULL;
+ const policydb_t *db = NULL;
+ unsigned int perm_max = 0;
+ size_t i, count = 0;
+
+ if (iter == NULL || (ps = qpol_iterator_state(iter)) == NULL ||
+ (db = qpol_iterator_policy(iter)) == NULL || perm_state_end(iter)) {
+ errno = EINVAL;
+ return 0; /* as a size_t 0 is error */
+ }
+
+ /* permission max is number of permissions in the class which includes
+ * the number of permissions in its common if it inherits one */
+ perm_max = db->class_val_to_struct[ps->obj_class_val - 1]->permissions.nprim;
+ if (perm_max > 32) {
+ errno = EDOM; /* perms set mask is a uint32_t cannot use more than 32 bits */
+ return 0; /* as a size_t 0 is error */
+ }
+
+ for (i = 0; i < perm_max; i++) {
+ if (ps->perm_set & 1 << i)
+ count++;
+ }
+
+ return count;
+}
diff --git a/libqpol/src/iterator_internal.h b/libqpol/src/iterator_internal.h
new file mode 100644
index 0000000..183724c
--- /dev/null
+++ b/libqpol/src/iterator_internal.h
@@ -0,0 +1,123 @@
+/**
+ * @file
+ * Declaration of the internal interface for
+ * qpol_iterator, an arbitrary valued policy component
+ * iterator used to return lists of components.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @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
+ */
+
+#ifndef QPOL_ITERATOR_INTERNAL_H
+#define QPOL_ITERATOR_INTERNAL_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/avtab.h>
+#include <qpol/iterator.h>
+#include <qpol/policy.h>
+#include <stddef.h>
+
+ typedef struct hash_state
+ {
+ unsigned int bucket;
+ hashtab_node_t *node;
+ hashtab_t *table;
+ } hash_state_t;
+
+ typedef struct ebitmap_state
+ {
+ ebitmap_t *bmap;
+ size_t cur;
+ } ebitmap_state_t;
+
+ typedef struct ocon_state
+ {
+ ocontext_t *head;
+ ocontext_t *cur;
+ } ocon_state_t;
+
+ typedef struct perm_state
+ {
+ uint32_t perm_set;
+ uint32_t obj_class_val;
+ uint8_t cur;
+ } perm_state_t;
+
+ typedef struct avtab_state
+ {
+ uint32_t rule_type_mask;
+ avtab_t *ucond_tab;
+ avtab_t *cond_tab;
+ uint32_t bucket;
+ avtab_ptr_t node;
+#define QPOL_AVTAB_STATE_AV 0
+#define QPOL_AVTAB_STATE_COND 1
+ unsigned which;
+ } avtab_state_t;
+
+ int qpol_iterator_create(const qpol_policy_t * policy, void *state,
+ void *(*get_cur) (const qpol_iterator_t * iter),
+ int (*next) (qpol_iterator_t * iter),
+ int (*end) (const qpol_iterator_t * iter),
+ size_t(*size) (const qpol_iterator_t * iter), void (*free_fn) (void *x), qpol_iterator_t ** iter);
+
+ void *qpol_iterator_state(const qpol_iterator_t * iter);
+ const policydb_t *qpol_iterator_policy(const qpol_iterator_t * iter);
+
+ void *hash_state_get_cur(const qpol_iterator_t * iter);
+ void *hash_state_get_cur_key(const qpol_iterator_t * iter);
+ void *ebitmap_state_get_cur_type(const qpol_iterator_t * iter);
+ void *ebitmap_state_get_cur_role(const qpol_iterator_t * iter);
+ void *ebitmap_state_get_cur_cat(const qpol_iterator_t * iter);
+ void *ebitmap_state_get_cur_permissive(const qpol_iterator_t * iter);
+ void *ebitmap_state_get_cur_polcap(const qpol_iterator_t * iter);
+ void *ocon_state_get_cur(const qpol_iterator_t * iter);
+ void *perm_state_get_cur(const qpol_iterator_t * iter);
+ void *avtab_state_get_cur(const qpol_iterator_t * iter);
+
+ int hash_state_next(qpol_iterator_t * iter);
+ int ebitmap_state_next(qpol_iterator_t * iter);
+ int ocon_state_next(qpol_iterator_t * iter);
+ int perm_state_next(qpol_iterator_t * iter);
+ int avtab_state_next(qpol_iterator_t * iter);
+
+ int hash_state_end(const qpol_iterator_t * iter);
+ int ebitmap_state_end(const qpol_iterator_t * iter);
+ int ocon_state_end(const qpol_iterator_t * iter);
+ int perm_state_end(const qpol_iterator_t * iter);
+ int avtab_state_end(const qpol_iterator_t * iter);
+
+ size_t hash_state_size(const qpol_iterator_t * iter);
+ size_t ebitmap_state_size(const qpol_iterator_t * iter);
+ size_t ocon_state_size(const qpol_iterator_t * iter);
+ size_t perm_state_size(const qpol_iterator_t * iter);
+ size_t avtab_state_size(const qpol_iterator_t * iter);
+
+ void ebitmap_state_destroy(void *es);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* QPOL_ITERATOR_INTERNAL_H */
diff --git a/libqpol/src/libqpol.map b/libqpol/src/libqpol.map
new file mode 100644
index 0000000..dd293bc
--- /dev/null
+++ b/libqpol/src/libqpol.map
@@ -0,0 +1,73 @@
+VERS_1.2 {
+ global:
+ qpol_avrule_*;
+ qpol_bool_*;
+ qpol_cat_*;
+ qpol_class_*;
+ qpol_common_*;
+ qpol_cond_*;
+ qpol_constraint_*;
+ qpol_context_*;
+ qpol_default_policy_find;
+ qpol_fs_use_*;
+ qpol_genfscon_*;
+ qpol_isid_*;
+ qpol_iterator_end;
+ qpol_iterator_next;
+ qpol_iterator_get_*;
+ qpol_iterator_destroy;
+ qpol_level_*;
+ qpol_mls_*;
+ qpol_module_*;
+ qpol_netifcon_*;
+ qpol_nodecon_*;
+ qpol_perm_*;
+ qpol_policy_append_module;
+ qpol_policy_build_syn_rule_table;
+ qpol_policy_destroy;
+ qpol_policy_get_*;
+ qpol_policy_has_capability;
+ qpol_policy_open_from_file;
+ qpol_policy_open_from_file_no_rules;
+ qpol_policy_open_from_memory;
+ qpol_policy_rebuild;
+ qpol_policy_reevaluate_conds;
+ qpol_portcon_*;
+ qpol_range_trans_*;
+ qpol_role_*;
+ qpol_syn_avrule_*;
+ qpol_syn_terule_*;
+ qpol_terule_*;
+ qpol_type_get_alias_iter;
+ qpol_type_get_attr_iter;
+ qpol_type_get_isalias;
+ qpol_type_get_isattr;
+ qpol_type_get_name;
+ qpol_type_get_type_iter;
+ qpol_type_get_value;
+ qpol_type_set_*;
+ qpol_user_*;
+ qpol_validatetrans_*;
+ libqpol_get_version;
+ local: *;
+};
+
+VERS_1.3 {
+ global:
+ qpol_policy_open_from_file;
+ qpol_policy_open_from_memory;
+ qpol_policy_rebuild;
+} VERS_1.2;
+
+VERS_1.4 {
+ global:
+ qpol_type_get_ispermissive;
+} VERS_1.3;
+
+VERS_1.5 {
+ global:
+ qpol_policy_permissive_*;
+ qpol_permissive_*;
+ qpol_policy_polcap_*;
+ qpol_polcap_*;
+} VERS_1.4;
diff --git a/libqpol/src/mls_query.c b/libqpol/src/mls_query.c
new file mode 100644
index 0000000..8c46acd
--- /dev/null
+++ b/libqpol/src/mls_query.c
@@ -0,0 +1,639 @@
+/**
+ * @file
+ * Implementation of the interface for searching and iterating over
+ * policy MLS components.
+ *
+ * @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
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <qpol/iterator.h>
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/expand.h>
+#include "iterator_internal.h"
+#include <qpol/mls_query.h>
+#include "qpol_internal.h"
+
+/* level */
+int qpol_policy_get_level_by_name(const qpol_policy_t * policy, const char *name, const qpol_level_t ** datum)
+{
+ policydb_t *db = NULL;
+ hashtab_datum_t internal_datum = NULL;
+
+ if (policy == NULL || name == NULL || datum == NULL) {
+ if (datum != NULL)
+ *datum = NULL;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+ db = &policy->p->p;
+ internal_datum = hashtab_search(db->p_levels.table, (const hashtab_key_t)name);
+ if (internal_datum == NULL) {
+ ERR(policy, "could not find datum for level %s", name);
+ errno = ENOENT;
+ return STATUS_ERR;
+ }
+ *datum = (qpol_level_t *) internal_datum;
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_policy_get_level_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter)
+{
+ policydb_t *db;
+ int error = 0;
+ hash_state_t *hs = NULL;
+
+ if (policy == NULL || iter == NULL) {
+ if (iter != NULL)
+ *iter = NULL;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+
+ hs = calloc(1, sizeof(hash_state_t));
+ if (hs == NULL) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = error;
+ return STATUS_ERR;
+ }
+ hs->table = &db->p_levels.table;
+ hs->node = (*(hs->table))->htable[0];
+
+ if (qpol_iterator_create(policy, (void *)hs, hash_state_get_cur,
+ hash_state_next, hash_state_end, hash_state_size, free, iter)) {
+ free(hs);
+ return STATUS_ERR;
+ }
+
+ if (hs->node == NULL)
+ hash_state_next(*iter);
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_level_get_isalias(const qpol_policy_t * policy, const qpol_level_t * datum, unsigned char *isalias)
+{
+ level_datum_t *internal_datum;
+
+ if (policy == NULL || datum == NULL || isalias == NULL) {
+ if (isalias != NULL)
+ *isalias = 0;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_datum = (level_datum_t *) datum;
+ *isalias = internal_datum->isalias;
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_level_get_value(const qpol_policy_t * policy, const qpol_level_t * datum, uint32_t * value)
+{
+ level_datum_t *internal_datum = NULL;
+
+ if (policy == NULL || datum == NULL || value == NULL) {
+ if (value != NULL)
+ *value = 0;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_datum = (level_datum_t *) datum;
+ *value = internal_datum->level->sens;
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_level_get_cat_iter(const qpol_policy_t * policy, const qpol_level_t * datum, qpol_iterator_t ** cats)
+{
+ level_datum_t *internal_datum = NULL;
+ ebitmap_state_t *es = NULL;
+ int error = 0;
+
+ if (policy == NULL || datum == NULL || cats == NULL) {
+ if (cats != NULL)
+ *cats = NULL;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_datum = (level_datum_t *) datum;
+
+ es = calloc(1, sizeof(ebitmap_state_t));
+ if (es == NULL) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = error;
+ return STATUS_ERR;
+ }
+
+ es->bmap = &(internal_datum->level->cat);
+ es->cur = es->bmap->node ? es->bmap->node->startbit : 0;
+
+ if (qpol_iterator_create(policy, es, ebitmap_state_get_cur_cat,
+ ebitmap_state_next, ebitmap_state_end, ebitmap_state_size, free, cats)) {
+ free(es);
+ return STATUS_ERR;
+ }
+
+ if (es->bmap->node && !ebitmap_get_bit(es->bmap, es->cur))
+ ebitmap_state_next(*cats);
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_level_get_name(const qpol_policy_t * policy, const qpol_level_t * datum, const char **name)
+{
+ level_datum_t *internal_datum = NULL;
+ policydb_t *db = NULL;
+
+ if (policy == NULL || datum == NULL || name == NULL) {
+ if (name != NULL)
+ *name = NULL;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+ internal_datum = (level_datum_t *) datum;
+
+ *name = db->p_sens_val_to_name[internal_datum->level->sens - 1];
+
+ return STATUS_SUCCESS;
+}
+
+typedef struct level_alias_hash_state
+{
+ unsigned int bucket;
+ hashtab_node_t *node;
+ hashtab_t *table;
+ uint32_t val;
+} level_alias_hash_state_t;
+
+static int hash_state_next_level_alias(qpol_iterator_t * iter)
+{
+ level_alias_hash_state_t *hs = NULL;
+ level_datum_t *datum = NULL;
+
+ if (iter == NULL) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+ hs = (level_alias_hash_state_t *) qpol_iterator_state(iter);
+ if (hs == NULL) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ if (hs->bucket >= (*(hs->table))->size) {
+ errno = ERANGE;
+ return STATUS_ERR;
+ }
+
+ do {
+ hash_state_next(iter);
+ datum = hs->node ? (level_datum_t *) hs->node->datum : NULL;
+ } while (datum != NULL && (datum->level->sens != hs->val || !datum->isalias));
+
+ return STATUS_SUCCESS;
+}
+
+static void *hash_state_get_cur_alias(const qpol_iterator_t * iter)
+{
+ level_alias_hash_state_t *hs = NULL;
+
+ if (iter == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ hs = (level_alias_hash_state_t *) qpol_iterator_state(iter);
+ if (hs == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ if (hs->bucket >= (*(hs->table))->size) {
+ errno = ERANGE;
+ return NULL;
+ }
+
+ return hs->node->key;
+}
+
+static size_t hash_state_level_alias_size(const qpol_iterator_t * iter)
+{
+ level_alias_hash_state_t *hs = NULL;
+ hashtab_node_t *tmp_node;
+ level_datum_t *tmp_lvl_datum;
+ uint32_t tmp_bucket = 0;
+ size_t count = 0;
+ if (iter == NULL || qpol_iterator_state(iter) == NULL) {
+ errno = EINVAL;
+ return 0;
+ }
+ hs = (level_alias_hash_state_t *) qpol_iterator_state(iter);
+ if (!hs) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+ for (tmp_bucket = 0; tmp_bucket < (*(hs->table))->size; tmp_bucket++) {
+ for (tmp_node = (*(hs->table))->htable[tmp_bucket]; tmp_node; tmp_node = tmp_node->next) {
+ tmp_lvl_datum = tmp_node ? tmp_node->datum : NULL;
+ if (tmp_lvl_datum) {
+ if (tmp_lvl_datum->isalias && tmp_lvl_datum->level->sens == hs->val)
+ count++;
+ }
+ }
+ }
+ return count;
+}
+
+int qpol_level_get_alias_iter(const qpol_policy_t * policy, const qpol_level_t * datum, qpol_iterator_t ** aliases)
+{
+ level_datum_t *internal_datum = NULL;
+ policydb_t *db = NULL;
+ int error;
+ level_alias_hash_state_t *hs = NULL;
+
+ if (policy == NULL || datum == NULL || aliases == NULL) {
+ if (aliases != NULL)
+ *aliases = NULL;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+ internal_datum = (level_datum_t *) datum;
+
+ hs = calloc(1, sizeof(level_alias_hash_state_t));
+ if (hs == NULL) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = error;
+ return STATUS_ERR;
+ }
+ hs->table = &db->p_levels.table;
+ hs->node = (*(hs->table))->htable[0];
+ hs->val = internal_datum->level->sens;
+
+ if (qpol_iterator_create(policy, (void *)hs, hash_state_get_cur_alias,
+ hash_state_next_level_alias, hash_state_end, hash_state_level_alias_size, free, aliases)) {
+ free(hs);
+ return STATUS_ERR;
+ }
+
+ if (hs->node == NULL || !((level_datum_t *) hs->node->datum)->isalias
+ || ((level_datum_t *) (hs->node->datum))->level->sens != hs->val)
+ hash_state_next_level_alias(*aliases);
+
+ return STATUS_SUCCESS;
+}
+
+/* cat */
+int qpol_policy_get_cat_by_name(const qpol_policy_t * policy, const char *name, const qpol_cat_t ** datum)
+{
+ hashtab_datum_t internal_datum;
+ policydb_t *db;
+
+ if (policy == NULL || name == NULL || datum == NULL) {
+ if (datum != NULL)
+ *datum = NULL;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+ internal_datum = hashtab_search(db->p_cats.table, (const hashtab_key_t)name);
+ if (internal_datum == NULL) {
+ *datum = NULL;
+ ERR(policy, "could not find datum for cat %s", name);
+ errno = ENOENT;
+ return STATUS_ERR;
+ }
+ *datum = (qpol_cat_t *) internal_datum;
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_policy_get_cat_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter)
+{
+ policydb_t *db;
+ int error = 0;
+ hash_state_t *hs = NULL;
+
+ if (policy == NULL || iter == NULL) {
+ if (iter != NULL)
+ *iter = NULL;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+
+ hs = calloc(1, sizeof(hash_state_t));
+ if (hs == NULL) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = error;
+ return STATUS_ERR;
+ }
+ hs->table = &db->p_cats.table;
+ hs->node = (*(hs->table))->htable[0];
+
+ if (qpol_iterator_create(policy, (void *)hs, hash_state_get_cur,
+ hash_state_next, hash_state_end, hash_state_size, free, iter)) {
+ free(hs);
+ return STATUS_ERR;
+ }
+
+ if (hs->node == NULL)
+ hash_state_next(*iter);
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_cat_get_value(const qpol_policy_t * policy, const qpol_cat_t * datum, uint32_t * value)
+{
+ cat_datum_t *internal_datum = NULL;
+
+ if (policy == NULL || datum == NULL || value == NULL) {
+ if (value != NULL)
+ *value = 0;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_datum = (cat_datum_t *) datum;
+ *value = internal_datum->s.value;
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_cat_get_isalias(const qpol_policy_t * policy, const qpol_cat_t * datum, unsigned char *isalias)
+{
+ cat_datum_t *internal_datum;
+
+ if (policy == NULL || datum == NULL || isalias == NULL) {
+ if (isalias != NULL)
+ *isalias = 0;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_datum = (cat_datum_t *) datum;
+ *isalias = internal_datum->isalias;
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_cat_get_name(const qpol_policy_t * policy, const qpol_cat_t * datum, const char **name)
+{
+ cat_datum_t *internal_datum = NULL;
+ policydb_t *db = NULL;
+
+ if (policy == NULL || datum == NULL || name == NULL) {
+ if (name != NULL)
+ *name = NULL;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+ internal_datum = (cat_datum_t *) datum;
+
+ *name = db->p_cat_val_to_name[internal_datum->s.value - 1];
+
+ return STATUS_SUCCESS;
+}
+
+static int hash_state_next_cat_alias(qpol_iterator_t * iter)
+{
+ /* using level alias state datum since data needed is identical */
+ level_alias_hash_state_t *hs = NULL;
+ cat_datum_t *datum = NULL;
+
+ if (iter == NULL) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+ hs = (level_alias_hash_state_t *) qpol_iterator_state(iter);
+ if (hs == NULL) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ if (hs->bucket >= (*(hs->table))->size) {
+ errno = ERANGE;
+ return STATUS_ERR;
+ }
+
+ do {
+ hash_state_next(iter);
+ datum = hs->node ? (cat_datum_t *) hs->node->datum : NULL;
+ } while (datum != NULL && (datum->s.value != hs->val || !datum->isalias));
+
+ return STATUS_SUCCESS;
+}
+
+static size_t hash_state_cat_alias_size(const qpol_iterator_t * iter)
+{
+ level_alias_hash_state_t *hs = NULL;
+ hashtab_node_t *tmp_node;
+ cat_datum_t *tmp_cat_datum;
+ uint32_t tmp_bucket = 0;
+ size_t count = 0;
+ if (iter == NULL || qpol_iterator_state(iter) == NULL) {
+ errno = EINVAL;
+ return 0;
+ }
+ hs = (level_alias_hash_state_t *) qpol_iterator_state(iter);
+ if (!hs) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+ for (tmp_bucket = 0; tmp_bucket < (*(hs->table))->size; tmp_bucket++) {
+ for (tmp_node = (*(hs->table))->htable[tmp_bucket]; tmp_node; tmp_node = tmp_node->next) {
+ tmp_cat_datum = tmp_node ? tmp_node->datum : NULL;
+ if (tmp_cat_datum) {
+ if (tmp_cat_datum->isalias && tmp_cat_datum->s.value == hs->val)
+ count++;
+ }
+ }
+ }
+ return count;
+}
+
+int qpol_cat_get_alias_iter(const qpol_policy_t * policy, const qpol_cat_t * datum, qpol_iterator_t ** aliases)
+{
+ cat_datum_t *internal_datum = NULL;
+ policydb_t *db = NULL;
+ int error;
+ level_alias_hash_state_t *hs = NULL;
+
+ if (policy == NULL || datum == NULL || aliases == NULL) {
+ if (aliases != NULL)
+ *aliases = NULL;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+ internal_datum = (cat_datum_t *) datum;
+
+ hs = calloc(1, sizeof(level_alias_hash_state_t));
+ if (hs == NULL) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = error;
+ return STATUS_ERR;
+ }
+ hs->table = &db->p_cats.table;
+ hs->node = (*(hs->table))->htable[0];
+ hs->val = internal_datum->s.value;
+
+ if (qpol_iterator_create(policy, (void *)hs, hash_state_get_cur_alias,
+ hash_state_next_cat_alias, hash_state_end, hash_state_cat_alias_size, free, aliases)) {
+ free(hs);
+ return STATUS_ERR;
+ }
+
+ if (hs->node == NULL || ((cat_datum_t *) (hs->node->datum))->s.value != hs->val)
+ hash_state_next_cat_alias(*aliases);
+
+ return STATUS_SUCCESS;
+}
+
+/* mls range */
+int qpol_mls_range_get_low_level(const qpol_policy_t * policy, const qpol_mls_range_t * range, const qpol_mls_level_t ** level)
+{
+ mls_range_t *internal_range = NULL;
+
+ if (policy == NULL || range == NULL || level == NULL) {
+ if (level != NULL)
+ *level = NULL;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_range = (mls_range_t *) range;
+ *level = (qpol_mls_level_t *) & (internal_range->level[0]);
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_mls_range_get_high_level(const qpol_policy_t * policy, const qpol_mls_range_t * range, const qpol_mls_level_t ** level)
+{
+ mls_range_t *internal_range = NULL;
+
+ if (policy == NULL || range == NULL || level == NULL) {
+ if (level != NULL)
+ *level = NULL;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_range = (mls_range_t *) range;
+ *level = (qpol_mls_level_t *) & (internal_range->level[1]);
+
+ return STATUS_SUCCESS;
+}
+
+/* mls_level */
+int qpol_mls_level_get_sens_name(const qpol_policy_t * policy, const qpol_mls_level_t * level, const char **name)
+{
+ policydb_t *db = NULL;
+ mls_level_t *internal_level = NULL;
+
+ if (policy == NULL || level == NULL || name == NULL) {
+ if (name != NULL)
+ *name = NULL;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_level = (mls_level_t *) level;
+ db = &policy->p->p;
+
+ *name = db->p_sens_val_to_name[internal_level->sens - 1];
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_mls_level_get_cat_iter(const qpol_policy_t * policy, const qpol_mls_level_t * level, qpol_iterator_t ** cats)
+{
+ mls_level_t *internal_level = NULL;
+ ebitmap_state_t *es = NULL;
+ int error = 0;
+
+ if (policy == NULL || level == NULL || cats == NULL) {
+ if (cats != NULL)
+ *cats = NULL;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_level = (mls_level_t *) level;
+
+ es = calloc(1, sizeof(ebitmap_state_t));
+ if (es == NULL) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = error;
+ return STATUS_ERR;
+ }
+
+ es->bmap = &(internal_level->cat);
+ es->cur = es->bmap->node ? es->bmap->node->startbit : 0;
+
+ if (qpol_iterator_create(policy, es, ebitmap_state_get_cur_cat,
+ ebitmap_state_next, ebitmap_state_end, ebitmap_state_size, free, cats)) {
+ free(es);
+ return STATUS_ERR;
+ }
+
+ if (es->bmap->node && !ebitmap_get_bit(es->bmap, es->cur))
+ ebitmap_state_next(*cats);
+
+ return STATUS_SUCCESS;
+}
diff --git a/libqpol/src/mlsrule_query.c b/libqpol/src/mlsrule_query.c
new file mode 100644
index 0000000..cc7e7a8
--- /dev/null
+++ b/libqpol/src/mlsrule_query.c
@@ -0,0 +1,230 @@
+/**
+ * @file
+ * Implementation for the public interface for searching and iterating over
+ * range transition rules.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @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
+ */
+
+#include "iterator_internal.h"
+#include <qpol/iterator.h>
+#include <qpol/policy.h>
+#include <qpol/mlsrule_query.h>
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/avtab.h>
+#include <sepol/policydb/util.h>
+#include <stdlib.h>
+#include "qpol_internal.h"
+
+typedef struct range_trans_state
+{
+ range_trans_t *head;
+ range_trans_t *cur;
+} range_trans_state_t;
+
+static int range_trans_state_end(const qpol_iterator_t * iter)
+{
+ range_trans_state_t *rs = NULL;
+
+ if (!iter || !(rs = qpol_iterator_state(iter))) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ return rs->cur ? 0 : 1;
+}
+
+static void *range_trans_state_get_cur(const qpol_iterator_t * iter)
+{
+ range_trans_state_t *rs = NULL;
+
+ if (!iter || !(rs = qpol_iterator_state(iter))) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ return rs->cur;
+}
+
+static int range_trans_state_next(qpol_iterator_t * iter)
+{
+ range_trans_state_t *rs = NULL;
+
+ if (!iter || !(rs = qpol_iterator_state(iter))) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ if (range_trans_state_end(iter)) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ rs->cur = rs->cur->next;
+
+ return STATUS_SUCCESS;
+}
+
+static size_t range_trans_state_size(const qpol_iterator_t * iter)
+{
+ range_trans_state_t *rs = NULL;
+ size_t count = 0;
+ range_trans_t *tmp = NULL;
+
+ if (!iter || !(rs = qpol_iterator_state(iter))) {
+ errno = EINVAL;
+ return 0;
+ }
+
+ for (tmp = rs->head; tmp; tmp = tmp->next)
+ count++;
+
+ return count;
+}
+
+int qpol_policy_get_range_trans_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter)
+{
+ policydb_t *db = NULL;
+ range_trans_state_t *rs = NULL;
+ int error = 0;
+
+ if (iter)
+ *iter = NULL;
+
+ if (!policy || !iter) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+
+ rs = calloc(1, sizeof(range_trans_state_t));
+ if (!rs) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ errno = error;
+ return STATUS_ERR;
+ }
+
+ if (qpol_iterator_create(policy, (void *)rs, range_trans_state_get_cur,
+ range_trans_state_next, range_trans_state_end, range_trans_state_size, free, iter)) {
+ error = errno;
+ free(rs);
+ errno = error;
+ return STATUS_ERR;
+ }
+
+ rs->head = rs->cur = db->range_tr;
+ return STATUS_SUCCESS;
+}
+
+int qpol_range_trans_get_source_type(const qpol_policy_t * policy, const qpol_range_trans_t * rule, const qpol_type_t ** source)
+{
+ policydb_t *db = NULL;
+ range_trans_t *rt = NULL;
+
+ if (source) {
+ *source = NULL;
+ }
+
+ if (!policy || !rule || !source) {
+ errno = EINVAL;
+ ERR(policy, "%s", strerror(EINVAL));
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+ rt = (range_trans_t *) rule;
+
+ *source = (qpol_type_t *) db->type_val_to_struct[rt->source_type - 1];
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_range_trans_get_target_type(const qpol_policy_t * policy, const qpol_range_trans_t * rule, const qpol_type_t ** target)
+{
+ policydb_t *db = NULL;
+ range_trans_t *rt = NULL;
+
+ if (target) {
+ *target = NULL;
+ }
+
+ if (!policy || !rule || !target) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+ rt = (range_trans_t *) rule;
+
+ *target = (qpol_type_t *) db->type_val_to_struct[rt->target_type - 1];
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_range_trans_get_target_class(const qpol_policy_t * policy, const qpol_range_trans_t * rule, const qpol_class_t ** target)
+{
+ policydb_t *db = NULL;
+ range_trans_t *rt = NULL;
+
+ if (target) {
+ *target = NULL;
+ }
+
+ if (!policy || !rule || !target) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+ rt = (range_trans_t *) rule;
+
+ *target = (qpol_class_t *) db->class_val_to_struct[rt->target_class - 1];
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_range_trans_get_range(const qpol_policy_t * policy, const qpol_range_trans_t * rule, const qpol_mls_range_t ** range)
+{
+ policydb_t *db = NULL;
+ range_trans_t *rt = NULL;
+
+ if (range) {
+ *range = NULL;
+ }
+
+ if (!policy || !rule || !range) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+ rt = (range_trans_t *) rule;
+
+ *range = (qpol_mls_range_t *) & rt->target_range;
+
+ return STATUS_SUCCESS;
+}
diff --git a/libqpol/src/module.c b/libqpol/src/module.c
new file mode 100644
index 0000000..35136d1
--- /dev/null
+++ b/libqpol/src/module.c
@@ -0,0 +1,236 @@
+/**
+ * @file
+ * Defines the public interface the QPol policy.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author Brandon Whalen bwhalen@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
+ */
+
+#include <config.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <qpol/module.h>
+#include <qpol/util.h>
+#include "qpol_internal.h"
+
+#include <sepol/policydb.h>
+#include <sepol/policydb/module.h>
+
+int qpol_module_create_from_file(const char *path, qpol_module_t ** module)
+{
+ sepol_module_package_t *smp = NULL;
+ sepol_policy_file_t *spf = NULL;
+ FILE *infile = NULL;
+ int error = 0;
+ char *tmp = NULL;
+ char *data = NULL;
+ ssize_t size;
+
+ if (module)
+ *module = NULL;
+
+ if (!path || !module) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ if (!(*module = calloc(1, sizeof(qpol_module_t)))) {
+ return STATUS_ERR;
+ }
+
+ if (!((*module)->path = strdup(path))) {
+ error = errno;
+ goto err;
+ }
+
+ if (sepol_policy_file_create(&spf)) {
+ error = errno;
+ goto err;
+ }
+
+ infile = fopen(path, "rb");
+ if (!infile) {
+ error = errno;
+ goto err;
+ }
+ size = qpol_bunzip(infile, &data);
+
+ if (size > 0) {
+ if (!qpol_is_data_mod_pkg(data)) {
+ error = ENOTSUP;
+ goto err;
+ }
+ sepol_policy_file_set_mem(spf, data, size);
+ } else {
+ if (!qpol_is_file_mod_pkg(infile)) {
+ error = ENOTSUP;
+ goto err;
+ }
+ rewind(infile);
+ sepol_policy_file_set_fp(spf, infile);
+ }
+
+ if (sepol_module_package_create(&smp)) {
+ error = EIO;
+ goto err;
+ }
+
+ if (sepol_module_package_info(spf, &((*module)->type), &((*module)->name), &tmp)) {
+ error = EIO;
+ goto err;
+ }
+ free(tmp);
+ tmp = NULL;
+ if (size > 0) {
+ // Re setting the memory location has the effect of rewind
+ // API is not accessible from here to explicitly "rewind" the
+ // in-memory file.
+ sepol_policy_file_set_mem(spf, data, size);
+ } else {
+ rewind(infile);
+ }
+
+ if (sepol_module_package_read(smp, spf, 0)) {
+ error = EIO;
+ goto err;
+ }
+
+ if (!((*module)->p = sepol_module_package_get_policy(smp))) {
+ error = EIO;
+ goto err;
+ }
+ /* set the module package's policy to NULL as the qpol module owns it now */
+ smp->policy = NULL;
+
+ (*module)->version = (*module)->p->p.version;
+ (*module)->enabled = 1;
+
+ sepol_module_package_free(smp);
+ fclose(infile);
+ if (data != NULL)
+ free (data);
+ sepol_policy_file_free(spf);
+
+ return STATUS_SUCCESS;
+
+ err:
+ qpol_module_destroy(module);
+ sepol_policy_file_free(spf);
+ sepol_module_package_free(smp);
+ if (infile)
+ fclose(infile);
+ if (data != NULL)
+ free (data);
+ if (tmp != NULL)
+ free(tmp);
+ errno = error;
+ return STATUS_ERR;
+}
+
+void qpol_module_destroy(qpol_module_t ** module)
+{
+ if (!module || !(*module))
+ return;
+
+ free((*module)->path);
+ free((*module)->name);
+ sepol_policydb_free((*module)->p);
+ free(*module);
+ *module = NULL;
+}
+
+int qpol_module_get_path(const qpol_module_t * module, const char **path)
+{
+ if (!module || !path) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ *path = module->path;
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_module_get_name(const qpol_module_t * module, const char **name)
+{
+ if (!module || !name) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ *name = module->name;
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_module_get_version(const qpol_module_t * module, const char **version)
+{
+ if (!module || !version) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ *version = module->version;
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_module_get_type(const qpol_module_t * module, int *type)
+{
+ if (!module || !type) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ *type = module->type;
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_module_get_enabled(const qpol_module_t * module, int *enabled)
+{
+ if (!module || !enabled) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ *enabled = module->enabled;
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_module_set_enabled(qpol_module_t * module, int enabled)
+{
+ if (!module) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ if (enabled != module->enabled && module->parent) {
+ module->parent->modified = 1;
+ }
+ module->enabled = enabled;
+
+ return STATUS_SUCCESS;
+}
diff --git a/libqpol/src/module_compiler.c b/libqpol/src/module_compiler.c
new file mode 100644
index 0000000..dc19798
--- /dev/null
+++ b/libqpol/src/module_compiler.c
@@ -0,0 +1,1440 @@
+/**
+ * @file
+ *
+ * This file is a copy of module_compiler.c from NSA's CVS repository.
+ *
+ * Author : Joshua Brindle <jbrindle@tresys.com>
+ * Karl MacMillan <kmacmillan@tresys.com>
+ * Jason Tang <jtang@tresys.com>
+ * Added support for binary policy modules
+ *
+ * Copyright (C) 2004 - 2005 Tresys Technology, LLC
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2.
+ */
+
+#include <config.h>
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/avrule_block.h>
+#include <sepol/policydb/conditional.h>
+
+#include "queue.h"
+#include "module_compiler.h"
+
+union stack_item_u
+{
+ avrule_block_t *avrule;
+ cond_list_t *cond_list;
+};
+
+typedef struct scope_stack
+{
+ union stack_item_u u;
+ int type; /* for above union: 1 = avrule block, 2 = conditional */
+ avrule_decl_t *decl; /* if in an avrule block, which
+ * declaration is current */
+ avrule_t *last_avrule;
+ int in_else; /* if in an avrule block, within ELSE branch */
+ int require_given; /* 1 if this block had at least one require */
+ struct scope_stack *parent, *child;
+} scope_stack_t;
+
+extern policydb_t *policydbp;
+extern queue_t id_queue;
+extern int yyerror(char *msg);
+extern void yyerror2(char *fmt, ...);
+
+static int push_stack(int stack_type, ...);
+static void pop_stack(void);
+
+/* keep track of the last item added to the stack */
+static scope_stack_t *stack_top = NULL;
+static avrule_block_t *last_block;
+static uint32_t next_decl_id = 1;
+
+int define_policy(int pass, int module_header_given)
+{
+ char *id;
+
+ if (module_header_given) {
+ if (policydbp->policy_type != POLICY_MOD) {
+ yyerror("Module specification found while not building a policy module.\n");
+ return -1;
+ }
+
+ if (pass == 2) {
+ while ((id = queue_remove(id_queue)) != NULL)
+ free(id);
+ } else {
+ id = (char *)queue_remove(id_queue);
+ if (!id) {
+ yyerror("no module name");
+ return -1;
+ }
+ policydbp->name = id;
+ if ((policydbp->version = queue_remove(id_queue)) == NULL) {
+ yyerror("Expected a module version but none was found.");
+ return -1;
+ }
+ }
+ } else {
+ if (policydbp->policy_type == POLICY_MOD) {
+ yyerror("Building a policy module, but no module specification found.\n");
+ return -1;
+ }
+ }
+ /* the first declaration within the global avrule
+ block will always have an id of 1 */
+ next_decl_id = 2;
+
+ /* reset the scoping stack */
+ while (stack_top != NULL) {
+ pop_stack();
+ }
+ if (push_stack(1, policydbp->global, policydbp->global->branch_list) == -1) {
+ return -1;
+ }
+ last_block = policydbp->global;
+ return 0;
+}
+
+/* Given the current parse stack, returns 1 if a declaration would be
+ * allowed here or 0 if not. For example, declarations are not
+ * allowed in conditionals, so if there are any conditionals in the
+ * current scope stack then this would return a 0.
+ */
+static int is_declaration_allowed(void)
+{
+ if (stack_top->type != 1 || stack_top->in_else) {
+ return 0;
+ }
+ return 1;
+}
+
+/* Attempt to declare a symbol within the current declaration. If
+ * currently within a non-conditional and in a non-else branch then
+ * insert the symbol, return 0 on success if symbol was undeclared.
+ * For roles and users, it is legal to have multiple declarations; as
+ * such return 1 to indicate that caller must free() the datum because
+ * it was not added. If symbols may not be declared here return -1.
+ * For duplicate declarations return -2. For all else, including out
+ * of memory, return -3. Note that dest_value and datum_value might
+ * not be restricted pointers. */
+int declare_symbol(uint32_t symbol_type, hashtab_key_t key, hashtab_datum_t datum, uint32_t * dest_value, uint32_t * datum_value)
+{
+ avrule_decl_t *decl = stack_top->decl;
+ int retval;
+
+ /* first check that symbols may be declared here */
+ if (!is_declaration_allowed()) {
+ return -1;
+ }
+ retval = symtab_insert(policydbp, symbol_type, key, datum, SCOPE_DECL, decl->decl_id, dest_value);
+ if (retval == 1 && dest_value) {
+ symtab_datum_t *s = (symtab_datum_t *) hashtab_search(policydbp->symtab[symbol_type].table,
+ key);
+ assert(s != NULL);
+
+ if (symbol_type == SYM_LEVELS) {
+ *dest_value = ((level_datum_t *) s)->level->sens;
+ } else {
+ *dest_value = s->value;
+ }
+ } else if (retval == -2) {
+ return -2;
+ } else if (retval < 0) {
+ return -3;
+ } else { /* fall through possible if retval is 0 */
+ }
+ if (datum_value != NULL) {
+ if (ebitmap_set_bit(decl->declared.scope + symbol_type, *datum_value - 1, 1)) {
+ return -3;
+ }
+ }
+ return retval;
+}
+
+static int role_implicit_bounds(hashtab_t roles_tab, char *role_id, role_datum_t * role)
+{
+ role_datum_t *bounds;
+ char *bounds_id, *delim;
+
+ delim = strrchr(role_id, '.');
+ if (!delim)
+ return 0; /* no implicit boundary */
+
+ bounds_id = strdup(role_id);
+ if (!bounds_id) {
+ yyerror("out of memory");
+ return -1;
+ }
+ bounds_id[(size_t) (delim - role_id)] = '\0';
+
+ bounds = hashtab_search(roles_tab, bounds_id);
+ if (!bounds) {
+ yyerror2("role %s doesn't exist, is implicit bounds of %s", bounds_id, role_id);
+ return -1;
+ }
+
+ if (!role->bounds)
+ role->bounds = bounds->s.value;
+ else if (role->bounds != bounds->s.value) {
+ yyerror2("role %s has inconsistent bounds %s/%s",
+ role_id, bounds_id, policydbp->p_role_val_to_name[role->bounds - 1]);
+ return -1;
+ }
+ free(bounds_id);
+
+ return 0;
+}
+
+role_datum_t *declare_role(void)
+{
+ char *id = queue_remove(id_queue), *dest_id = NULL;
+ role_datum_t *role = NULL, *dest_role = NULL;
+ int retval;
+ uint32_t value;
+
+ if (id == NULL) {
+ yyerror("no role name");
+ return NULL;
+ }
+ if ((role = (role_datum_t *) malloc(sizeof(*role))) == NULL) {
+ yyerror("Out of memory!");
+ free(id);
+ return NULL;
+ }
+ role_datum_init(role);
+
+ retval = declare_symbol(SYM_ROLES, id, (hashtab_datum_t *) role, &value, &value);
+ if (retval == 0) {
+ role->s.value = value;
+ if ((dest_id = strdup(id)) == NULL) {
+ yyerror("Out of memory!");
+ return NULL;
+ }
+ } else {
+ /* this role was already declared in this module, or error */
+ dest_id = id;
+ role_datum_destroy(role);
+ free(role);
+ }
+ if (retval == 0 || retval == 1) {
+ /* create a new role_datum_t for this decl, if necessary */
+ hashtab_t roles_tab;
+ assert(stack_top->type == 1);
+ if (stack_top->parent == NULL) {
+ /* in parent, so use global symbol table */
+ roles_tab = policydbp->p_roles.table;
+ } else {
+ roles_tab = stack_top->decl->p_roles.table;
+ }
+ dest_role = (role_datum_t *) hashtab_search(roles_tab, dest_id);
+ if (dest_role == NULL) {
+ if ((dest_role = (role_datum_t *) malloc(sizeof(*dest_role))) == NULL) {
+ yyerror("Out of memory!");
+ free(dest_id);
+ return NULL;
+ }
+ role_datum_init(dest_role);
+ dest_role->s.value = value;
+ if (role_implicit_bounds(roles_tab, dest_id, dest_role)) {
+ free(dest_id);
+ role_datum_destroy(dest_role);
+ free(dest_role);
+ return NULL;
+ }
+ if (hashtab_insert(roles_tab, dest_id, dest_role)) {
+ yyerror("Out of memory!");
+ free(dest_id);
+ role_datum_destroy(dest_role);
+ free(dest_role);
+ return NULL;
+ }
+ } else {
+ free(dest_id);
+ }
+ } else {
+ free(dest_id);
+ }
+ switch (retval) {
+ case -3:{
+ yyerror("Out of memory!");
+ return NULL;
+ }
+ case -2:{
+ yyerror("duplicate declaration of role");
+ return NULL;
+ }
+ case -1:{
+ yyerror("could not declare role here");
+ return NULL;
+ }
+ case 0:{
+ if (ebitmap_set_bit(&dest_role->dominates, role->s.value - 1, 1)) {
+ yyerror("out of memory");
+ return NULL;
+ }
+ return dest_role;
+ }
+ case 1:{
+ return dest_role; /* role already declared for this block */
+ }
+ default:{
+ assert(0); /* should never get here */
+ }
+ }
+}
+
+type_datum_t *declare_type(unsigned char primary, unsigned char isattr)
+{
+ char *id;
+ type_datum_t *typdatum;
+ int retval;
+ uint32_t value = 0;
+
+ id = (char *)queue_remove(id_queue);
+ if (!id) {
+ yyerror("no type/attribute name?");
+ return NULL;
+ }
+ if (strcmp(id, "self") == 0) {
+ yyerror("'self' is a reserved type name and may not be declared.");
+ free(id);
+ return NULL;
+ }
+
+ typdatum = (type_datum_t *) malloc(sizeof(type_datum_t));
+ if (!typdatum) {
+ yyerror("Out of memory!");
+ free(id);
+ return NULL;
+ }
+ type_datum_init(typdatum);
+ typdatum->primary = primary;
+ typdatum->flavor = isattr ? TYPE_ATTRIB : TYPE_TYPE;
+
+ retval = declare_symbol(SYM_TYPES, id, typdatum, &value, &value);
+ if (retval == 0 || retval == 1) {
+ if (typdatum->primary) {
+ typdatum->s.value = value;
+ }
+ } else {
+ /* error occurred (can't have duplicate type declarations) */
+ free(id);
+ type_datum_destroy(typdatum);
+ free(typdatum);
+ }
+ switch (retval) {
+ case -3:{
+ yyerror("Out of memory!");
+ return NULL;
+ }
+ case -2:{
+ yyerror2("duplicate declaration of type/attribute");
+ return NULL;
+ }
+ case -1:{
+ yyerror("could not declare type/attribute here");
+ return NULL;
+ }
+ case 0:
+ case 1:{
+ return typdatum;
+ }
+ default:{
+ assert(0); /* should never get here */
+ }
+ }
+}
+
+static int user_implicit_bounds(hashtab_t users_tab, char *user_id, user_datum_t * user)
+{
+ user_datum_t *bounds;
+ char *bounds_id, *delim;
+
+ delim = strrchr(user_id, '.');
+ if (!delim)
+ return 0; /* no implicit boundary */
+
+ bounds_id = strdup(user_id);
+ if (!bounds_id) {
+ yyerror("out of memory");
+ return -1;
+ }
+ bounds_id[(size_t) (delim - user_id)] = '\0';
+
+ bounds = hashtab_search(users_tab, bounds_id);
+ if (!bounds) {
+ yyerror2("user %s doesn't exist, is implicit bounds of %s", bounds_id, user_id);
+ return -1;
+ }
+
+ if (!user->bounds)
+ user->bounds = bounds->s.value;
+ else if (user->bounds != bounds->s.value) {
+ yyerror2("user %s has inconsistent bounds %s/%s",
+ user_id, bounds_id, policydbp->p_role_val_to_name[user->bounds - 1]);
+ return -1;
+ }
+ free(bounds_id);
+
+ return 0;
+}
+
+user_datum_t *declare_user(void)
+{
+ char *id = queue_remove(id_queue), *dest_id = NULL;
+ user_datum_t *user = NULL, *dest_user = NULL;
+ int retval;
+ uint32_t value = 0;
+
+ if (id == NULL) {
+ yyerror("no user name");
+ return NULL;
+ }
+ if ((user = (user_datum_t *) malloc(sizeof(*user))) == NULL) {
+ yyerror("Out of memory!");
+ free(id);
+ return NULL;
+ }
+ user_datum_init(user);
+
+ retval = declare_symbol(SYM_USERS, id, (hashtab_datum_t *) user, &value, &value);
+
+ if (retval == 0) {
+ user->s.value = value;
+ if ((dest_id = strdup(id)) == NULL) {
+ yyerror("Out of memory!");
+ return NULL;
+ }
+ } else {
+ /* this user was already declared in this module, or error */
+ dest_id = id;
+ user_datum_destroy(user);
+ free(user);
+ }
+ if (retval == 0 || retval == 1) {
+ /* create a new user_datum_t for this decl, if necessary */
+ hashtab_t users_tab;
+ assert(stack_top->type == 1);
+ if (stack_top->parent == NULL) {
+ /* in parent, so use global symbol table */
+ users_tab = policydbp->p_users.table;
+ } else {
+ users_tab = stack_top->decl->p_users.table;
+ }
+ dest_user = (user_datum_t *) hashtab_search(users_tab, dest_id);
+ if (dest_user == NULL) {
+ if ((dest_user = (user_datum_t *) malloc(sizeof(*dest_user))) == NULL) {
+ yyerror("Out of memory!");
+ free(dest_id);
+ return NULL;
+ }
+ user_datum_init(dest_user);
+ dest_user->s.value = value;
+ if (user_implicit_bounds(users_tab, dest_id, dest_user)) {
+ free(dest_id);
+ user_datum_destroy(dest_user);
+ free(dest_user);
+ return NULL;
+ }
+ if (hashtab_insert(users_tab, dest_id, dest_user)) {
+ yyerror("Out of memory!");
+ free(dest_id);
+ user_datum_destroy(dest_user);
+ free(dest_user);
+ return NULL;
+ }
+ } else {
+ free(dest_id);
+ }
+ } else {
+ free(dest_id);
+ }
+ switch (retval) {
+ case -3:{
+ yyerror("Out of memory!");
+ return NULL;
+ }
+ case -2:{
+ yyerror("duplicate declaration of user");
+ return NULL;
+ }
+ case -1:{
+ yyerror("could not declare user here");
+ return NULL;
+ }
+ case 0:{
+ return dest_user;
+ }
+ case 1:{
+ return dest_user; /* user already declared for this block */
+ }
+ default:{
+ assert(0); /* should never get here */
+ }
+ }
+}
+
+/* Return a type_datum_t for the local avrule_decl with the given ID.
+ * If it does not exist, create one with the same value as 'value'.
+ * This function assumes that the ID is within scope. c.f.,
+ * is_id_in_scope().
+ *
+ * NOTE: this function usurps ownership of id afterwards. The caller
+ * shall not reference it nor free() it afterwards.
+ */
+type_datum_t *get_local_type(char *id, uint32_t value, unsigned char isattr)
+{
+ type_datum_t *dest_typdatum;
+ hashtab_t types_tab;
+ assert(stack_top->type == 1);
+ if (stack_top->parent == NULL) {
+ /* in global, so use global symbol table */
+ types_tab = policydbp->p_types.table;
+ } else {
+ types_tab = stack_top->decl->p_types.table;
+ }
+ dest_typdatum = hashtab_search(types_tab, id);
+ if (!dest_typdatum) {
+ dest_typdatum = (type_datum_t *) malloc(sizeof(type_datum_t));
+ if (dest_typdatum == NULL) {
+ free(id);
+ return NULL;
+ }
+ type_datum_init(dest_typdatum);
+ dest_typdatum->s.value = value;
+ dest_typdatum->flavor = isattr ? TYPE_ATTRIB : TYPE_TYPE;
+ dest_typdatum->primary = 1;
+ if (hashtab_insert(types_tab, id, dest_typdatum)) {
+ free(id);
+ type_datum_destroy(dest_typdatum);
+ free(dest_typdatum);
+ return NULL;
+ }
+
+ } else {
+ free(id);
+ if (dest_typdatum->flavor != isattr ? TYPE_ATTRIB : TYPE_TYPE) {
+ return NULL;
+ }
+ }
+ return dest_typdatum;
+}
+
+/* Given the current parse stack, returns 1 if a requirement would be
+ * allowed here or 0 if not. For example, the ELSE branch may never
+ * have its own requirements.
+ */
+static int is_require_allowed(void)
+{
+ if (stack_top->type == 1 && !stack_top->in_else) {
+ return 1;
+ }
+ return 0;
+}
+
+/* Attempt to require a symbol within the current scope. If currently
+ * within an optional (and not its else branch), add the symbol to the
+ * required list. Return 0 on success, 1 if caller needs to free()
+ * datum. If symbols may not be declared here return -1. For duplicate
+ * declarations return -2. For all else, including out of memory,
+ * return -3.. Note that dest_value and datum_value might not be
+ * restricted pointers.
+ */
+int require_symbol(uint32_t symbol_type, hashtab_key_t key, hashtab_datum_t datum, uint32_t * dest_value, uint32_t * datum_value)
+{
+ avrule_decl_t *decl = stack_top->decl;
+ int retval;
+
+ /* first check that symbols may be required here */
+ if (!is_require_allowed()) {
+ return -1;
+ }
+ retval = symtab_insert(policydbp, symbol_type, key, datum, SCOPE_REQ, decl->decl_id, dest_value);
+ if (retval == 1) {
+ symtab_datum_t *s = (symtab_datum_t *) hashtab_search(policydbp->symtab[symbol_type].table,
+ key);
+ assert(s != NULL);
+
+ if (symbol_type == SYM_LEVELS) {
+ *dest_value = ((level_datum_t *) s)->level->sens;
+ } else {
+ *dest_value = s->value;
+ }
+ } else if (retval == -2) {
+ /* ignore require statements if that symbol was
+ * previously declared and is in current scope */
+ int prev_declaration_ok = 0;
+ if (is_id_in_scope(symbol_type, key)) {
+ if (symbol_type == SYM_TYPES) {
+ /* check that previous symbol has same
+ * type/attribute-ness */
+ unsigned char new_isattr = ((type_datum_t *) datum)->flavor;
+ type_datum_t *old_datum = (type_datum_t *) hashtab_search(policydbp->symtab[SYM_TYPES].table, key);
+ assert(old_datum != NULL);
+ unsigned char old_isattr = old_datum->flavor;
+ prev_declaration_ok = (old_isattr == new_isattr ? 1 : 0);
+ } else {
+ prev_declaration_ok = 1;
+ }
+ }
+ if (prev_declaration_ok) {
+ /* ignore this require statement because it
+ * was already declared within my scope */
+ stack_top->require_given = 1;
+ return 1;
+ } else {
+ /* previous declaration was not in scope or
+ * had a mismatched type/attribute, so
+ * generate an error */
+ return -2;
+ }
+ } else if (retval < 0) {
+ return -3;
+ } else { /* fall through possible if retval is 0 or 1 */
+ }
+ if (datum_value != NULL) {
+ if (ebitmap_set_bit(decl->required.scope + symbol_type, *datum_value - 1, 1)) {
+ return -3;
+ }
+ }
+ stack_top->require_given = 1;
+ return retval;
+}
+
+int add_perm_to_class(uint32_t perm_value, uint32_t class_value)
+{
+ avrule_decl_t *decl = stack_top->decl;
+ scope_index_t *scope;
+
+ assert(perm_value >= 1);
+ assert(class_value >= 1);
+ scope = &decl->required;
+ if (class_value > scope->class_perms_len) {
+ int i;
+ ebitmap_t *new_map = realloc(scope->class_perms_map,
+ class_value * sizeof(*new_map));
+ if (new_map == NULL) {
+ return -1;
+ }
+ scope->class_perms_map = new_map;
+ for (i = scope->class_perms_len; i < class_value; i++) {
+ ebitmap_init(scope->class_perms_map + i);
+ }
+ scope->class_perms_len = class_value;
+ }
+ if (ebitmap_set_bit(scope->class_perms_map + class_value - 1, perm_value - 1, 1)) {
+ return -1;
+ }
+ return 0;
+}
+
+static int perm_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p __attribute__ ((unused)))
+{
+ if (key)
+ free(key);
+ free(datum);
+ return 0;
+}
+
+static void class_datum_destroy(class_datum_t * cladatum)
+{
+ if (cladatum != NULL) {
+ hashtab_map(cladatum->permissions.table, perm_destroy, NULL);
+ hashtab_destroy(cladatum->permissions.table);
+ free(cladatum);
+ }
+}
+
+int require_class(int pass)
+{
+ char *class_id = queue_remove(id_queue);
+ char *perm_id = NULL;
+ class_datum_t *datum = NULL;
+ perm_datum_t *perm = NULL;
+ int ret;
+
+ if (pass == 2) {
+ free(class_id);
+ while ((perm_id = queue_remove(id_queue)) != NULL)
+ free(perm_id);
+ return 0;
+ }
+
+ /* first add the class if it is not already there */
+ if (class_id == NULL) {
+ yyerror("no class name for class definition?");
+ return -1;
+ }
+
+ if ((datum = calloc(1, sizeof(*datum))) == NULL || symtab_init(&datum->permissions, PERM_SYMTAB_SIZE)) {
+ yyerror("Out of memory!");
+ goto cleanup;
+ }
+ ret = require_symbol(SYM_CLASSES, class_id, datum, &datum->s.value, &datum->s.value);
+ switch (ret) {
+ case -3:{
+ yyerror("Out of memory!");
+ free(class_id);
+ class_datum_destroy(datum);
+ goto cleanup;
+ }
+ case -2:{
+ yyerror("duplicate declaration of class");
+ free(class_id);
+ class_datum_destroy(datum);
+ goto cleanup;
+ }
+ case -1:{
+ yyerror("could not require class here");
+ free(class_id);
+ class_datum_destroy(datum);
+ goto cleanup;
+ }
+ case 0:{
+ /* a new class was added; reindex everything */
+ if (policydb_index_classes(policydbp)) {
+ yyerror("Out of memory!");
+ goto cleanup;
+ }
+ break;
+ }
+ case 1:{
+ class_datum_destroy(datum);
+ datum = hashtab_search(policydbp->p_classes.table, class_id);
+ assert(datum); /* the class datum should have existed */
+ free(class_id);
+ break;
+ }
+ default:{
+ assert(0); /* should never get here */
+ }
+ }
+
+ /* now add each of the permissions to this class's requirements */
+ while ((perm_id = queue_remove(id_queue)) != NULL) {
+ int allocated = 0;
+
+ /* Is the permission already in the table? */
+ perm = hashtab_search(datum->permissions.table, perm_id);
+ if (!perm && datum->comdatum)
+ perm = hashtab_search(datum->comdatum->permissions.table, perm_id);
+ if (perm) {
+ /* Yes, drop the name. */
+ free(perm_id);
+ } else {
+ /* No - allocate and insert an entry for it. */
+ if (policydbp->policy_type == POLICY_BASE) {
+ yyerror2("Base policy - require of permission %s without prior declaration.", perm_id);
+ free(perm_id);
+ goto cleanup;
+ }
+ allocated = 1;
+ if ((perm = malloc(sizeof(*perm))) == NULL) {
+ yyerror("Out of memory!");
+ free(perm_id);
+ goto cleanup;
+ }
+ memset(perm, 0, sizeof(*perm));
+ ret = hashtab_insert(datum->permissions.table, perm_id, perm);
+ if (ret) {
+ yyerror("Out of memory!");
+ free(perm_id);
+ free(perm);
+ goto cleanup;
+ }
+ perm->s.value = datum->permissions.nprim + 1;
+ }
+
+ if (add_perm_to_class(perm->s.value, datum->s.value) == -1) {
+ yyerror("Out of memory!");
+ goto cleanup;
+ }
+
+ /* Update number of primitives if we allocated one. */
+ if (allocated)
+ datum->permissions.nprim++;
+ }
+ return 0;
+ cleanup:
+ return -1;
+}
+
+int require_role(int pass)
+{
+ char *id = queue_remove(id_queue);
+ role_datum_t *role = NULL;
+ int retval;
+ if (pass == 2) {
+ free(id);
+ return 0;
+ }
+ if (id == NULL) {
+ yyerror("no role name");
+ return -1;
+ }
+ if ((role = malloc(sizeof(*role))) == NULL) {
+ free(id);
+ yyerror("Out of memory!");
+ return -1;
+ }
+ role_datum_init(role);
+ retval = require_symbol(SYM_ROLES, id, (hashtab_datum_t *) role, &role->s.value, &role->s.value);
+ if (retval != 0) {
+ free(id);
+ role_datum_destroy(role);
+ free(role);
+ }
+ switch (retval) {
+ case -3:{
+ yyerror("Out of memory!");
+ return -1;
+ }
+ case -2:{
+ yyerror("duplicate declaration of role");
+ return -1;
+ }
+ case -1:{
+ yyerror("could not require role here");
+ return -1;
+ }
+ case 0:{
+ /* all roles dominate themselves */
+ if (ebitmap_set_bit(&role->dominates, role->s.value - 1, 1)) {
+ yyerror("Out of memory");
+ return -1;
+ }
+ return 0;
+ }
+ case 1:{
+ return 0; /* role already required */
+ }
+ default:{
+ assert(0); /* should never get here */
+ }
+ }
+}
+
+static int require_type_or_attribute(int pass, unsigned char isattr)
+{
+ char *id = queue_remove(id_queue);
+ type_datum_t *type = NULL;
+ int retval;
+ if (pass == 2) {
+ free(id);
+ return 0;
+ }
+ if (id == NULL) {
+ yyerror("no type name");
+ return -1;
+ }
+ if ((type = malloc(sizeof(*type))) == NULL) {
+ free(id);
+ yyerror("Out of memory!");
+ return -1;
+ }
+ type_datum_init(type);
+ type->primary = 1;
+ type->flavor = isattr ? TYPE_ATTRIB : TYPE_TYPE;
+ retval = require_symbol(SYM_TYPES, id, (hashtab_datum_t *) type, &type->s.value, &type->s.value);
+ if (retval != 0) {
+ free(id);
+ free(type);
+ }
+ switch (retval) {
+ case -3:{
+ yyerror("Out of memory!");
+ return -1;
+ }
+ case -2:{
+ yyerror("duplicate declaration of type/attribute");
+ return -1;
+ }
+ case -1:{
+ yyerror("could not require type/attribute here");
+ return -1;
+ }
+ case 0:{
+ return 0;
+ }
+ case 1:{
+ return 0; /* type already required */
+ }
+ default:{
+ assert(0); /* should never get here */
+ }
+ }
+}
+
+int require_type(int pass)
+{
+ return require_type_or_attribute(pass, 0);
+}
+
+int require_attribute(int pass)
+{
+ return require_type_or_attribute(pass, 1);
+}
+
+int require_user(int pass)
+{
+ char *id = queue_remove(id_queue);
+ user_datum_t *user = NULL;
+ int retval;
+ if (pass == 1) {
+ free(id);
+ return 0;
+ }
+ if (id == NULL) {
+ yyerror("no user name");
+ return -1;
+ }
+ if ((user = malloc(sizeof(*user))) == NULL) {
+ free(id);
+ yyerror("Out of memory!");
+ return -1;
+ }
+ user_datum_init(user);
+ retval = require_symbol(SYM_USERS, id, (hashtab_datum_t *) user, &user->s.value, &user->s.value);
+ if (retval != 0) {
+ free(id);
+ user_datum_destroy(user);
+ }
+ switch (retval) {
+ case -3:{
+ yyerror("Out of memory!");
+ return -1;
+ }
+ case -2:{
+ yyerror("duplicate declaration of user");
+ return -1;
+ }
+ case -1:{
+ yyerror("could not require user here");
+ return -1;
+ }
+ case 0:{
+ return 0;
+ }
+ case 1:{
+ return 0; /* user already required */
+ }
+ default:{
+ assert(0); /* should never get here */
+ }
+ }
+}
+
+int require_bool(int pass)
+{
+ char *id = queue_remove(id_queue);
+ cond_bool_datum_t *booldatum = NULL;
+ int retval;
+ if (pass == 2) {
+ free(id);
+ return 0;
+ }
+ if (id == NULL) {
+ yyerror("no boolean name");
+ return -1;
+ }
+ if ((booldatum = calloc(1, sizeof(*booldatum))) == NULL) {
+ cond_destroy_bool(id, booldatum, NULL);
+ yyerror("Out of memory!");
+ return -1;
+ }
+ retval = require_symbol(SYM_BOOLS, id, (hashtab_datum_t *) booldatum, &booldatum->s.value, &booldatum->s.value);
+ if (retval != 0) {
+ cond_destroy_bool(id, booldatum, NULL);
+ }
+ switch (retval) {
+ case -3:{
+ yyerror("Out of memory!");
+ return -1;
+ }
+ case -2:{
+ yyerror("duplicate declaration of boolean");
+ return -1;
+ }
+ case -1:{
+ yyerror("could not require boolean here");
+ return -1;
+ }
+ case 0:{
+ return 0;
+ }
+ case 1:{
+ return 0; /* boolean already required */
+ }
+ default:{
+ assert(0); /* should never get here */
+ }
+ }
+}
+
+int require_sens(int pass)
+{
+ char *id = queue_remove(id_queue);
+ level_datum_t *level = NULL;
+ int retval;
+ if (pass == 2) {
+ free(id);
+ return 0;
+ }
+ if (!id) {
+ yyerror("no sensitivity name");
+ return -1;
+ }
+ level = malloc(sizeof(level_datum_t));
+ if (!level) {
+ free(id);
+ yyerror("Out of memory!");
+ return -1;
+ }
+ level_datum_init(level);
+ level->level = malloc(sizeof(mls_level_t));
+ if (!level->level) {
+ free(id);
+ level_datum_destroy(level);
+ free(level);
+ yyerror("Out of memory!");
+ return -1;
+ }
+ mls_level_init(level->level);
+ retval = require_symbol(SYM_LEVELS, id, (hashtab_datum_t *) level, &level->level->sens, &level->level->sens);
+ if (retval != 0) {
+ free(id);
+ mls_level_destroy(level->level);
+ free(level->level);
+ level_datum_destroy(level);
+ free(level);
+ }
+ switch (retval) {
+ case -3:{
+ yyerror("Out of memory!");
+ return -1;
+ }
+ case -2:{
+ yyerror("duplicate declaration of sensitivity");
+ return -1;
+ }
+ case -1:{
+ yyerror("could not require sensitivity here");
+ return -1;
+ }
+ case 0:{
+ return 0;
+ }
+ case 1:{
+ return 0; /* sensitivity already required */
+ }
+ default:{
+ assert(0); /* should never get here */
+ }
+ }
+}
+
+int require_cat(int pass)
+{
+ char *id = queue_remove(id_queue);
+ cat_datum_t *cat = NULL;
+ int retval;
+ if (pass == 2) {
+ free(id);
+ return 0;
+ }
+ if (!id) {
+ yyerror("no category name");
+ return -1;
+ }
+ cat = malloc(sizeof(cat_datum_t));
+ if (!cat) {
+ free(id);
+ yyerror("Out of memory!");
+ return -1;
+ }
+ cat_datum_init(cat);
+
+ retval = require_symbol(SYM_CATS, id, (hashtab_datum_t *) cat, &cat->s.value, &cat->s.value);
+ if (retval != 0) {
+ free(id);
+ cat_datum_destroy(cat);
+ free(cat);
+ }
+ switch (retval) {
+ case -3:{
+ yyerror("Out of memory!");
+ return -1;
+ }
+ case -2:{
+ yyerror("duplicate declaration of category");
+ return -1;
+ }
+ case -1:{
+ yyerror("could not require category here");
+ return -1;
+ }
+ case 0:{
+ return 0;
+ }
+ case 1:{
+ return 0; /* category already required */
+ }
+ default:{
+ assert(0); /* should never get here */
+ }
+ }
+}
+
+static int is_scope_in_stack(scope_datum_t * scope, scope_stack_t * stack)
+{
+ int i;
+ if (stack == NULL) {
+ return 0; /* no matching scope found */
+ }
+ if (stack->type == 1) {
+ avrule_decl_t *decl = stack->decl;
+ for (i = 0; i < scope->decl_ids_len; i++) {
+ if (scope->decl_ids[i] == decl->decl_id) {
+ return 1;
+ }
+ }
+ } else {
+ /* note that conditionals can't declare or require
+ * symbols, so skip this level */
+ }
+
+ /* not within scope of this stack, so try its parent */
+ return is_scope_in_stack(scope, stack->parent);
+}
+
+int is_id_in_scope(uint32_t symbol_type, hashtab_key_t id)
+{
+ scope_datum_t *scope = (scope_datum_t *) hashtab_search(policydbp->scope[symbol_type].table, id);
+ if (scope == NULL) {
+ return 1; /* id is not known, so return success */
+ }
+ return is_scope_in_stack(scope, stack_top);
+}
+
+static int is_perm_in_scope_index(uint32_t perm_value, uint32_t class_value, scope_index_t * scope)
+{
+ if (class_value > scope->class_perms_len) {
+ return 1;
+ }
+ if (ebitmap_get_bit(scope->class_perms_map + class_value - 1, perm_value - 1)) {
+ return 1;
+ }
+ return 0;
+}
+
+static int is_perm_in_stack(uint32_t perm_value, uint32_t class_value, scope_stack_t * stack)
+{
+ if (stack == NULL) {
+ return 0; /* no matching scope found */
+ }
+ if (stack->type == 1) {
+ avrule_decl_t *decl = stack->decl;
+ if (is_perm_in_scope_index(perm_value, class_value, &decl->required)
+ || is_perm_in_scope_index(perm_value, class_value, &decl->declared)) {
+ return 1;
+ }
+ } else {
+ /* note that conditionals can't declare or require
+ * symbols, so skip this level */
+ }
+
+ /* not within scope of this stack, so try its parent */
+ return is_perm_in_stack(perm_value, class_value, stack->parent);
+}
+
+int is_perm_in_scope(hashtab_key_t perm_id, hashtab_key_t class_id)
+{
+ class_datum_t *cladatum = (class_datum_t *) hashtab_search(policydbp->p_classes.table,
+ class_id);
+ perm_datum_t *perdatum;
+ if (cladatum == NULL) {
+ return 1;
+ }
+ perdatum = (perm_datum_t *) hashtab_search(cladatum->permissions.table, perm_id);
+ if (perdatum == NULL) {
+ return 1;
+ }
+ return is_perm_in_stack(perdatum->s.value, cladatum->s.value, stack_top);
+}
+
+cond_list_t *get_current_cond_list(cond_list_t * cond)
+{
+ /* FIX ME: do something different here if in a nested
+ * conditional? */
+ avrule_decl_t *decl = stack_top->decl;
+ return get_decl_cond_list(policydbp, decl, cond);
+}
+
+/* Append the new conditional node to the existing ones. During
+ * expansion the list will be reversed -- i.e., the last AV rule will
+ * be the first one listed in the policy. This matches the behavior
+ * of the upstream compiler. */
+void append_cond_list(cond_list_t * cond)
+{
+ cond_list_t *old_cond = get_current_cond_list(cond);
+ avrule_t *tmp;
+ assert(old_cond != NULL); /* probably out of memory */
+ if (old_cond->avtrue_list == NULL) {
+ old_cond->avtrue_list = cond->avtrue_list;
+ } else {
+ for (tmp = old_cond->avtrue_list; tmp->next != NULL; tmp = tmp->next) ;
+ tmp->next = cond->avtrue_list;
+ }
+ if (old_cond->avfalse_list == NULL) {
+ old_cond->avfalse_list = cond->avfalse_list;
+ } else {
+ for (tmp = old_cond->avfalse_list; tmp->next != NULL; tmp = tmp->next) ;
+ tmp->next = cond->avfalse_list;
+ }
+}
+
+void append_avrule(avrule_t * avrule)
+{
+ avrule_decl_t *decl = stack_top->decl;
+
+ /* currently avrules follow a completely different code path
+ * for handling avrules and compute types
+ * (define_cond_avrule_te_avtab, define_cond_compute_type);
+ * therefore there ought never be a conditional on top of the
+ * scope stack */
+ assert(stack_top->type == 1);
+
+ if (stack_top->last_avrule == NULL) {
+ decl->avrules = avrule;
+ } else {
+ stack_top->last_avrule->next = avrule;
+ }
+ stack_top->last_avrule = avrule;
+}
+
+/* this doesn't actually append, but really prepends it */
+void append_role_trans(role_trans_rule_t * role_tr_rules)
+{
+ avrule_decl_t *decl = stack_top->decl;
+
+ /* role transitions are not allowed within conditionals */
+ assert(stack_top->type == 1);
+
+ role_tr_rules->next = decl->role_tr_rules;
+ decl->role_tr_rules = role_tr_rules;
+}
+
+/* this doesn't actually append, but really prepends it */
+void append_role_allow(role_allow_rule_t * role_allow_rules)
+{
+ avrule_decl_t *decl = stack_top->decl;
+
+ /* role allows are not allowed within conditionals */
+ assert(stack_top->type == 1);
+
+ role_allow_rules->next = decl->role_allow_rules;
+ decl->role_allow_rules = role_allow_rules;
+}
+
+/* this doesn't actually append, but really prepends it */
+void append_range_trans(range_trans_rule_t * range_tr_rules)
+{
+ avrule_decl_t *decl = stack_top->decl;
+
+ /* range transitions are not allowed within conditionals */
+ assert(stack_top->type == 1);
+
+ range_tr_rules->next = decl->range_tr_rules;
+ decl->range_tr_rules = range_tr_rules;
+}
+
+int begin_optional(int pass)
+{
+ avrule_block_t *block = NULL;
+ avrule_decl_t *decl;
+ if (pass == 1) {
+ /* allocate a new avrule block for this optional block */
+ if ((block = avrule_block_create()) == NULL || (decl = avrule_decl_create(next_decl_id)) == NULL) {
+ goto cleanup;
+ }
+ block->flags |= AVRULE_OPTIONAL;
+ block->branch_list = decl;
+ last_block->next = block;
+ } else {
+ /* select the next block from the chain built during pass 1 */
+ block = last_block->next;
+ assert(block != NULL && block->branch_list != NULL && block->branch_list->decl_id == next_decl_id);
+ decl = block->branch_list;
+ }
+ if (push_stack(1, block, decl) == -1) {
+ goto cleanup;
+ }
+ stack_top->last_avrule = NULL;
+ last_block = block;
+ next_decl_id++;
+ return 0;
+ cleanup:
+ yyerror("Out of memory!");
+ avrule_block_destroy(block);
+ return -1;
+}
+
+int end_optional(int pass)
+{
+ /* once nested conditionals are allowed, do the stack unfolding here */
+ pop_stack();
+ return 0;
+}
+
+int begin_optional_else(int pass)
+{
+ avrule_decl_t *decl;
+ assert(stack_top->type == 1 && stack_top->in_else == 0);
+ if (pass == 1) {
+ /* allocate a new declaration and add it to the
+ * current chain */
+ if ((decl = avrule_decl_create(next_decl_id)) == NULL) {
+ yyerror("Out of memory!");
+ return -1;
+ }
+ stack_top->decl->next = decl;
+ } else {
+ /* pick the (hopefully last) declaration of this
+ avrule block, built from pass 1 */
+ decl = stack_top->decl->next;
+ assert(decl != NULL && decl->next == NULL && decl->decl_id == next_decl_id);
+ }
+ stack_top->in_else = 1;
+ stack_top->decl = decl;
+ stack_top->last_avrule = NULL;
+ stack_top->require_given = 0;
+ next_decl_id++;
+ return 0;
+}
+
+static int copy_requirements(avrule_decl_t * dest, scope_stack_t * stack)
+{
+ int i;
+ if (stack == NULL) {
+ return 0;
+ }
+ if (stack->type == 1) {
+ scope_index_t *src_scope = &stack->decl->required;
+ scope_index_t *dest_scope = &dest->required;
+ for (i = 0; i < SYM_NUM; i++) {
+ ebitmap_t *src_bitmap = &src_scope->scope[i];
+ ebitmap_t *dest_bitmap = &dest_scope->scope[i];
+ if (ebitmap_union(dest_bitmap, src_bitmap)) {
+ yyerror("Out of memory!");
+ return -1;
+ }
+ }
+ /* now copy class permissions */
+ if (src_scope->class_perms_len > dest_scope->class_perms_len) {
+ ebitmap_t *new_map = realloc(dest_scope->class_perms_map,
+ src_scope->class_perms_len * sizeof(*new_map));
+ if (new_map == NULL) {
+ yyerror("Out of memory!");
+ return -1;
+ }
+ dest_scope->class_perms_map = new_map;
+ for (i = dest_scope->class_perms_len; i < src_scope->class_perms_len; i++) {
+ ebitmap_init(dest_scope->class_perms_map + i);
+ }
+ dest_scope->class_perms_len = src_scope->class_perms_len;
+ }
+ for (i = 0; i < src_scope->class_perms_len; i++) {
+ ebitmap_t *src_bitmap = &src_scope->class_perms_map[i];
+ ebitmap_t *dest_bitmap = &dest_scope->class_perms_map[i];
+ if (ebitmap_union(dest_bitmap, src_bitmap)) {
+ yyerror("Out of memory!");
+ return -1;
+ }
+ }
+ }
+ return copy_requirements(dest, stack->parent);
+}
+
+/* During pass 1, check that at least one thing was required within
+ * this block, for those places where a REQUIRED is necessary. During
+ * pass 2, have this block inherit its parents' requirements. Return
+ * 0 on success, -1 on failure. */
+int end_avrule_block(int pass)
+{
+ avrule_decl_t *decl = stack_top->decl;
+ assert(stack_top->type == 1);
+ if (pass == 2) {
+ /* this avrule_decl inherits all of its parents'
+ * requirements */
+ if (copy_requirements(decl, stack_top->parent) == -1) {
+ return -1;
+ }
+ return 0;
+ }
+ if (!stack_top->in_else && !stack_top->require_given) {
+ if (policydbp->policy_type == POLICY_BASE && stack_top->parent != NULL) {
+ /* if this is base no require should be in the global block */
+ return 0;
+ } else {
+ /* non-ELSE branches must have at least one thing required */
+ yyerror("This block has no require section.");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/* Push a new scope on to the stack and update the 'last' pointer.
+ * Return 0 on success, -1 if out * of memory. */
+static int push_stack(int stack_type, ...)
+{
+ scope_stack_t *s = calloc(1, sizeof(*s));
+ va_list ap;
+ if (s == NULL) {
+ return -1;
+ }
+ va_start(ap, stack_type);
+ switch (s->type = stack_type) {
+ case 1:{
+ s->u.avrule = va_arg(ap, avrule_block_t *);
+ s->decl = va_arg(ap, avrule_decl_t *);
+ break;
+ }
+ case 2:{
+ s->u.cond_list = va_arg(ap, cond_list_t *);
+ break;
+ }
+ default:
+ /* invalid stack type given */
+ assert(0);
+ }
+ va_end(ap);
+ s->parent = stack_top;
+ s->child = NULL;
+ stack_top = s;
+ return 0;
+}
+
+/* Pop off the most recently added from the stack. Update the 'last'
+ * pointer. */
+static void pop_stack(void)
+{
+ scope_stack_t *parent;
+ assert(stack_top != NULL);
+ parent = stack_top->parent;
+ if (parent != NULL) {
+ parent->child = NULL;
+ }
+ free(stack_top);
+ stack_top = parent;
+}
diff --git a/libqpol/src/module_compiler.h b/libqpol/src/module_compiler.h
new file mode 100644
index 0000000..489086d
--- /dev/null
+++ b/libqpol/src/module_compiler.h
@@ -0,0 +1,115 @@
+/**
+ * @file
+ *
+ * This file is a copy of module_compiler.h from NSA's CVS repository.
+ *
+ * Author : Joshua Brindle <jbrindle@tresys.com>
+ * Karl MacMillan <kmacmillan@tresys.com>
+ * Jason Tang <jtang@tresys.com>
+ * Added support for binary policy modules
+ *
+ * Copyright (C) 2004 - 2005 Tresys Technology, LLC
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2.
+ */
+
+#ifndef MODULE_COMPILER_H
+#define MODULE_COMPILER_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <sepol/policydb/hashtab.h>
+
+/* Called when checkpolicy begins to parse a policy -- either at the
+ * very beginning for a kernel/base policy, or after the module header
+ * for policy modules. Initialize the memory structures within.
+ * Return 0 on success, -1 on error. */
+int define_policy(int pass, int module_header_given);
+
+/* Declare a symbol declaration to the current avrule_decl. Check
+ * that insertion is allowed here and that the symbol does not already
+ * exist. Returns 0 on success, 1 if symbol was already there (caller
+ * needs to free() the datum), -1 if declarations not allowed, -2 for
+ * duplicate declarations, -3 for all else.
+ */
+int declare_symbol(uint32_t symbol_type, hashtab_key_t key, hashtab_datum_t datum, uint32_t * dest_value, uint32_t * datum_value);
+
+role_datum_t *declare_role(void);
+type_datum_t *declare_type(unsigned char primary, unsigned char isattr);
+user_datum_t *declare_user(void);
+
+type_datum_t *get_local_type(char *id, uint32_t value, unsigned char isattr);
+
+/* Add a symbol to the current avrule_block's require section. Note
+ * that a module may not both declare and require the same symbol.
+ * Returns 0 on success, -1 on error. */
+int require_symbol(uint32_t symbol_type, hashtab_key_t key, hashtab_datum_t datum, uint32_t * dest_value, uint32_t * datum_value);
+
+/* Enable a permission for a class within the current avrule_decl.
+ * Return 0 on success, -1 if out of memory. */
+int add_perm_to_class(uint32_t perm_value, uint32_t class_value);
+
+/* Functions called from REQUIRE blocks. Add the first symbol on the
+ * id_queue to this avrule_decl's scope if not already there.
+ * c.f. require_symbol(). */
+int require_class(int pass);
+int require_role(int pass);
+int require_type(int pass);
+int require_attribute(int pass);
+int require_user(int pass);
+int require_bool(int pass);
+int require_sens(int pass);
+int require_cat(int pass);
+
+/* Check if an identifier is within the scope of the current
+ * declaration or any of its parents. Return 1 if it is, 0 if not.
+ * If the identifier is not known at all then return 1 (truth). */
+int is_id_in_scope(uint32_t symbol_type, hashtab_key_t id);
+
+/* Check if a particular permission is within the scope of the current
+ * declaration or any of its parents. Return 1 if it is, 0 if not.
+ * If the identifier is not known at all then return 1 (truth). */
+int is_perm_in_scope(hashtab_key_t perm_id, hashtab_key_t class_id);
+
+/* Search the current avrules block for a conditional with the same
+ * expression as 'cond'. If the conditional does not exist then
+ * create one. Either way, return the conditional. */
+cond_list_t *get_current_cond_list(cond_list_t * cond);
+
+/* Append rule to the current avrule_block. */
+void append_cond_list(cond_list_t * cond);
+void append_avrule(avrule_t * avrule);
+void append_role_trans(role_trans_rule_t * role_tr_rules);
+void append_role_allow(role_allow_rule_t * role_allow_rules);
+void append_range_trans(range_trans_rule_t * range_tr_rules);
+
+/* Create a new optional block and add it to the global policy.
+ * During the second pass resolve the block's requirements. Return 0
+ * on success, -1 on error.
+ */
+int begin_optional(int pass);
+int end_optional(int pass);
+
+/* ELSE blocks are similar to normal blocks with the following two
+ * limitations:
+ * - no declarations are allowed within else branches
+ * - no REQUIRES are allowed; the else branch inherits the parent's
+ * requirements
+ */
+int begin_optional_else(int pass);
+
+/* Called whenever existing an avrule block. Check that the block had
+ * a non-empty REQUIRE section. If so pop the block off of the scop
+ * stack and return 0. If not then send an error to yyerror and
+ * return -1. */
+int end_avrule_block(int pass);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libqpol/src/netifcon_query.c b/libqpol/src/netifcon_query.c
new file mode 100644
index 0000000..2f39757
--- /dev/null
+++ b/libqpol/src/netifcon_query.c
@@ -0,0 +1,159 @@
+/**
+* @file
+* Defines the public interface for searching and iterating over netifcon statements.
+*
+* @author Kevin Carr kcarr@tresys.com
+* @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
+*/
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <qpol/iterator.h>
+#include <qpol/policy.h>
+#include <qpol/context_query.h>
+#include <qpol/netifcon_query.h>
+#include <sepol/policydb/policydb.h>
+#include "qpol_internal.h"
+#include "iterator_internal.h"
+
+int qpol_policy_get_netifcon_by_name(const qpol_policy_t * policy, const char *name, const qpol_netifcon_t ** ocon)
+{
+ ocontext_t *tmp = NULL;
+ policydb_t *db = NULL;
+
+ if (ocon != NULL)
+ *ocon = NULL;
+
+ if (policy == NULL || name == NULL || ocon == NULL) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+ for (tmp = db->ocontexts[OCON_NETIF]; tmp; tmp = tmp->next) {
+ if (!strcmp(name, tmp->u.name))
+ break;
+ }
+
+ *ocon = (qpol_netifcon_t *) tmp;
+
+ if (*ocon == NULL) {
+ ERR(policy, "could not find netifcon statement for %s", name);
+ errno = ENOENT;
+ return STATUS_ERR;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_policy_get_netifcon_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter)
+{
+ policydb_t *db = NULL;
+ int error = 0;
+ ocon_state_t *os = NULL;
+
+ if (iter != NULL)
+ *iter = NULL;
+
+ if (policy == NULL || iter == NULL) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+
+ os = calloc(1, sizeof(ocon_state_t));
+ if (os == NULL) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = error;
+ return STATUS_ERR;
+ }
+
+ os->head = os->cur = db->ocontexts[OCON_NETIF];
+
+ if (qpol_iterator_create(policy, (void *)os, ocon_state_get_cur,
+ ocon_state_next, ocon_state_end, ocon_state_size, free, iter)) {
+ free(os);
+ return STATUS_ERR;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_netifcon_get_name(const qpol_policy_t * policy, const qpol_netifcon_t * ocon, const char **name)
+{
+ ocontext_t *internal_ocon = NULL;
+
+ if (name != NULL)
+ *name = NULL;
+
+ if (policy == NULL || ocon == NULL || name == NULL) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_ocon = (ocontext_t *) ocon;
+ *name = internal_ocon->u.name;
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_netifcon_get_msg_con(const qpol_policy_t * policy, const qpol_netifcon_t * ocon, const qpol_context_t ** context)
+{
+ ocontext_t *internal_ocon = NULL;
+
+ if (context != NULL)
+ *context = NULL;
+
+ if (policy == NULL || ocon == NULL || context == NULL) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_ocon = (ocontext_t *) ocon;
+ *context = (qpol_context_t *) & (internal_ocon->context[1]);
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_netifcon_get_if_con(const qpol_policy_t * policy, const qpol_netifcon_t * ocon, const qpol_context_t ** context)
+{
+ ocontext_t *internal_ocon = NULL;
+
+ if (context != NULL)
+ *context = NULL;
+
+ if (policy == NULL || ocon == NULL || context == NULL) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_ocon = (ocontext_t *) ocon;
+ *context = (qpol_context_t *) & (internal_ocon->context[0]);
+
+ return STATUS_SUCCESS;
+}
diff --git a/libqpol/src/nodecon_query.c b/libqpol/src/nodecon_query.c
new file mode 100644
index 0000000..4a91a1f
--- /dev/null
+++ b/libqpol/src/nodecon_query.c
@@ -0,0 +1,329 @@
+/**
+* @file
+* Defines the public interface for searching and iterating over nodecon statements.
+*
+* @author Kevin Carr kcarr@tresys.com
+* @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
+*/
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <qpol/iterator.h>
+#include <qpol/policy.h>
+#include <qpol/context_query.h>
+#include <qpol/nodecon_query.h>
+#include <sepol/policydb/policydb.h>
+#include "qpol_internal.h"
+#include "iterator_internal.h"
+
+struct qpol_nodecon
+{
+ ocontext_t *ocon;
+ unsigned char protocol;
+};
+
+int qpol_policy_get_nodecon_by_node(const qpol_policy_t * policy, uint32_t addr[4], uint32_t mask[4], unsigned char protocol,
+ qpol_nodecon_t ** ocon)
+{
+ policydb_t *db = NULL;
+ ocontext_t *tmp = NULL;
+ int error = 0;
+
+ if (ocon != NULL)
+ *ocon = NULL;
+
+ if (policy == NULL || ocon == NULL) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+
+ for (tmp = db->ocontexts[(protocol == QPOL_IPV4 ? OCON_NODE : OCON_NODE6)]; tmp; tmp = tmp->next) {
+ if (protocol == QPOL_IPV4) {
+ if (addr[0] != tmp->u.node.addr || mask[0] != tmp->u.node.mask)
+ continue;
+ } else {
+ if (memcmp(addr, tmp->u.node6.addr, 16) || memcmp(mask, tmp->u.node6.mask, 16))
+ continue;
+ }
+ *ocon = calloc(1, sizeof(qpol_nodecon_t));
+ if (*ocon == NULL) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ errno = error;
+ return STATUS_ERR;
+ }
+
+ (*ocon)->protocol = protocol == QPOL_IPV4 ? QPOL_IPV4 : QPOL_IPV6;
+ (*ocon)->ocon = tmp;
+ }
+
+ if (*ocon == NULL) {
+ ERR(policy, "%s", "could not find nodecon statement for node");
+ errno = ENOENT;
+ return STATUS_ERR;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+typedef struct node_state
+{
+ ocon_state_t *v4state;
+ ocon_state_t *v6state;
+} node_state_t;
+
+static void node_state_free(void *ns)
+{
+ node_state_t *ins = (node_state_t *) ns;
+
+ if (!ns)
+ return;
+
+ free(ins->v4state);
+ free(ins->v6state);
+ free(ns);
+}
+
+static int node_state_end(const qpol_iterator_t * iter)
+{
+ node_state_t *ns = NULL;
+
+ if (iter == NULL || qpol_iterator_state(iter) == NULL) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ ns = (node_state_t *) qpol_iterator_state(iter);
+
+ return (ns->v4state->cur == NULL && ns->v6state->cur == NULL);
+}
+
+static void *node_state_get_cur(const qpol_iterator_t * iter)
+{
+ node_state_t *ns = NULL;
+ qpol_nodecon_t *node = NULL;
+
+ if (iter == NULL || qpol_iterator_state(iter) == NULL || node_state_end(iter)) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ ns = (node_state_t *) qpol_iterator_state(iter);
+
+ node = calloc(1, sizeof(qpol_nodecon_t));
+ if (!node) {
+ return NULL;
+ }
+
+ node->ocon = ns->v4state->cur ? ns->v4state->cur : ns->v6state->cur;
+ node->protocol = ns->v4state->cur ? QPOL_IPV4 : QPOL_IPV6;
+
+ return node;
+}
+
+static size_t node_state_size(const qpol_iterator_t * iter)
+{
+ node_state_t *ns = NULL;
+ size_t count = 0;
+ ocontext_t *ocon = NULL;
+
+ if (iter == NULL || qpol_iterator_state(iter) == NULL) {
+ errno = EINVAL;
+ return 0;
+ }
+
+ ns = (node_state_t *) qpol_iterator_state(iter);
+
+ if (ns->v4state)
+ for (ocon = ns->v4state->head; ocon; ocon = ocon->next)
+ count++;
+
+ if (ns->v6state)
+ for (ocon = ns->v6state->head; ocon; ocon = ocon->next)
+ count++;
+
+ return count;
+}
+
+static int node_state_next(qpol_iterator_t * iter)
+{
+ node_state_t *ns = NULL;
+
+ if (iter == NULL || qpol_iterator_state(iter) == NULL) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ ns = (node_state_t *) qpol_iterator_state(iter);
+
+ if (ns->v4state->cur == NULL && ns->v6state->cur == NULL) {
+ errno = ERANGE;
+ return STATUS_ERR;
+ }
+
+ if (ns->v4state->cur)
+ ns->v4state->cur = ns->v4state->cur->next;
+ else
+ ns->v6state->cur = ns->v6state->cur->next;
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_policy_get_nodecon_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter)
+{
+ policydb_t *db = NULL;
+ int error = 0;
+ ocon_state_t *v4os = NULL, *v6os = NULL;
+ node_state_t *ns = NULL;
+
+ if (iter != NULL)
+ *iter = NULL;
+
+ if (policy == NULL || iter == NULL) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+
+ v4os = calloc(1, sizeof(ocon_state_t));
+ if (v4os == NULL) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = error;
+ return STATUS_ERR;
+ }
+ v4os->head = v4os->cur = db->ocontexts[OCON_NODE];
+
+ v6os = calloc(1, sizeof(ocon_state_t));
+ if (v6os == NULL) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ free(v4os);
+ errno = error;
+ return STATUS_ERR;
+ }
+ v6os->head = v6os->cur = db->ocontexts[OCON_NODE6];
+
+ ns = calloc(1, sizeof(node_state_t));
+ if (ns == NULL) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ free(v4os);
+ free(v6os);
+ errno = error;
+ return STATUS_ERR;
+ }
+ ns->v4state = v4os;
+ ns->v6state = v6os;
+
+ if (qpol_iterator_create(policy, (void *)ns, node_state_get_cur,
+ node_state_next, node_state_end, node_state_size, node_state_free, iter)) {
+ node_state_free(ns);
+ return STATUS_ERR;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_nodecon_get_addr(const qpol_policy_t * policy, const qpol_nodecon_t * ocon, uint32_t ** addr, unsigned char *protocol)
+{
+ if (addr != NULL)
+ *addr = NULL;
+ if (protocol != NULL)
+ *protocol = 0;
+
+ if (policy == NULL || ocon == NULL || addr == NULL || protocol == NULL) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ *protocol = ocon->protocol;
+
+ if (ocon->protocol == QPOL_IPV4) {
+ *addr = &(ocon->ocon->u.node.addr);
+ } else {
+ *addr = ocon->ocon->u.node6.addr;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_nodecon_get_mask(const qpol_policy_t * policy, const qpol_nodecon_t * ocon, uint32_t ** mask, unsigned char *protocol)
+{
+ if (mask != NULL)
+ *mask = NULL;
+ if (protocol != NULL)
+ *protocol = 0;
+
+ if (policy == NULL || ocon == NULL || mask == NULL || protocol == NULL) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ *protocol = ocon->protocol;
+
+ if (ocon->protocol == QPOL_IPV4) {
+ *mask = &(ocon->ocon->u.node.mask);
+ } else {
+ *mask = ocon->ocon->u.node6.mask;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_nodecon_get_protocol(const qpol_policy_t * policy, const qpol_nodecon_t * ocon, unsigned char *protocol)
+{
+ if (protocol != NULL)
+ *protocol = 0;
+
+ if (policy == NULL || ocon == NULL || protocol == NULL) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ *protocol = ocon->protocol;
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_nodecon_get_context(const qpol_policy_t * policy, const qpol_nodecon_t * ocon, const qpol_context_t ** context)
+{
+ if (context != NULL)
+ *context = NULL;
+
+ if (policy == NULL || ocon == NULL || context == NULL) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ *context = (qpol_context_t *) & (ocon->ocon->context[0]);
+
+ return STATUS_SUCCESS;
+}
diff --git a/libqpol/src/permissive_query.c b/libqpol/src/permissive_query.c
new file mode 100644
index 0000000..df601c2
--- /dev/null
+++ b/libqpol/src/permissive_query.c
@@ -0,0 +1,95 @@
+/**
+* @file
+* Defines the public interface for searching and iterating over the permissive types.
+*
+* @author Steve Lawrence slawrence@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
+*/
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <qpol/iterator.h>
+#include <qpol/policy.h>
+#include <qpol/permissive_query.h>
+#include <sepol/policydb/policydb.h>
+#include "qpol_internal.h"
+#include "iterator_internal.h"
+
+
+int qpol_permissive_get_name(const qpol_policy_t *policy, const qpol_permissive_t * datum, const char **name)
+{
+ type_datum_t *internal_datum = NULL;
+ policydb_t *db = NULL;
+
+ if (policy == NULL || datum == NULL || name == NULL) {
+ if (name != NULL)
+ *name = NULL;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+ internal_datum = (type_datum_t *)datum;
+
+ *name = db->p_type_val_to_name[internal_datum->s.value - 1];
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_policy_get_permissive_iter(const qpol_policy_t *policy, qpol_iterator_t **iter)
+{
+ int error = 0;
+ policydb_t *db;
+ ebitmap_state_t *state = NULL;
+
+ if (iter) {
+ *iter = NULL;
+ }
+
+ if (policy == NULL || iter == NULL) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+
+ state = calloc(1, sizeof(ebitmap_state_t));
+ if (state == NULL) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = error;
+ return STATUS_ERR;
+ }
+
+ state->bmap = &(db->permissive_map);
+ state->cur = state->bmap->node ? state->bmap->node->startbit : 0;
+
+ if (qpol_iterator_create(policy, state, ebitmap_state_get_cur_permissive,
+ ebitmap_state_next, ebitmap_state_end, ebitmap_state_size, free, iter)) {
+ free(state);
+ return STATUS_ERR;
+ }
+
+ if (state->bmap->node && !ebitmap_get_bit(state->bmap, state->cur))
+ ebitmap_state_next(*iter);
+
+ return STATUS_SUCCESS;
+}
diff --git a/libqpol/src/polcap_query.c b/libqpol/src/polcap_query.c
new file mode 100644
index 0000000..019536f
--- /dev/null
+++ b/libqpol/src/polcap_query.c
@@ -0,0 +1,92 @@
+/**
+* @file
+* Defines the public interface for searching and iterating over the policy capabilities.
+*
+* @author Steve Lawrence slawrence@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
+*/
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <qpol/iterator.h>
+#include <qpol/policy.h>
+#include <qpol/polcap_query.h>
+#include <sepol/policydb/policydb.h>
+#include "qpol_internal.h"
+#include "iterator_internal.h"
+
+
+int qpol_polcap_get_name(const qpol_policy_t *policy, const qpol_polcap_t * datum, const char **name)
+{
+ char *internal_datum = NULL;
+
+ if (policy == NULL || datum == NULL || name == NULL) {
+ if (name != NULL)
+ *name = NULL;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_datum = (char *) datum;
+ *name = internal_datum;
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_policy_get_polcap_iter(const qpol_policy_t *policy, qpol_iterator_t **iter)
+{
+ int error = 0;
+ policydb_t *db;
+ ebitmap_state_t *state = NULL;
+
+ if (iter) {
+ *iter = NULL;
+ }
+
+ if (policy == NULL || iter == NULL) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+
+ state = calloc(1, sizeof(ebitmap_state_t));
+ if (state == NULL) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = error;
+ return STATUS_ERR;
+ }
+
+ state->bmap = &(db->policycaps);
+ state->cur = state->bmap->node ? state->bmap->node->startbit : 0;
+
+ if (qpol_iterator_create(policy, state, ebitmap_state_get_cur_polcap,
+ ebitmap_state_next, ebitmap_state_end, ebitmap_state_size, free, iter)) {
+ free(state);
+ return STATUS_ERR;
+ }
+
+ if (state->bmap->node && !ebitmap_get_bit(state->bmap, state->cur))
+ ebitmap_state_next(*iter);
+
+ return STATUS_SUCCESS;
+}
diff --git a/libqpol/src/policy.c b/libqpol/src/policy.c
new file mode 100644
index 0000000..7180556
--- /dev/null
+++ b/libqpol/src/policy.c
@@ -0,0 +1,1563 @@
+/**
+ * @file
+ * Defines the public interface the QPol policy.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author Brandon Whalen bwhalen@tresys.com
+ * @author Jeremy Solt jsolt@tresys.com
+ *
+ * Copyright (C) 2006-2008 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
+ */
+
+#include <config.h>
+
+#include "qpol_internal.h"
+#include <assert.h>
+#include <byteswap.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <asm/types.h>
+
+#include <sepol/debug.h>
+#include <sepol/handle.h>
+#include <sepol/policydb/flask_types.h>
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/conditional.h>
+#include <sepol/policydb.h>
+#include <sepol/module.h>
+#include <sepol/policydb/module.h>
+#include <sepol/policydb/avrule_block.h>
+
+#include <stdbool.h>
+#include <qpol/iterator.h>
+#include <qpol/policy.h>
+#include <qpol/policy_extend.h>
+#include "expand.h"
+#include "queue.h"
+#include "iterator_internal.h"
+
+/* redefine input so we can read from a string */
+/* borrowed from O'Reilly lex and yacc pg 157 */
+char *qpol_src_originalinput;
+char *qpol_src_input;
+char *qpol_src_inputptr; /* current position in qpol_src_input */
+char *qpol_src_inputlim; /* end of data */
+
+extern void init_scanner(void);
+extern int yyparse(void);
+extern void init_parser(int, int);
+extern queue_t id_queue;
+extern unsigned int policydb_errors;
+extern unsigned long policydb_lineno;
+extern char source_file[];
+extern policydb_t *policydbp;
+extern int mlspol;
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define cpu_to_le16(x) (x)
+#define le16_to_cpu(x) (x)
+#define cpu_to_le32(x) (x)
+#define le32_to_cpu(x) (x)
+#define cpu_to_le64(x) (x)
+#define le64_to_cpu(x) (x)
+#else
+#define cpu_to_le16(x) bswap_16(x)
+#define le16_to_cpu(x) bswap_16(x)
+#define cpu_to_le32(x) bswap_32(x)
+#define le32_to_cpu(x) bswap_32(x)
+#define cpu_to_le64(x) bswap_64(x)
+#define le64_to_cpu(x) bswap_64(x)
+#endif
+
+/* buffer for reading from file */
+typedef struct fbuf
+{
+ char *buf;
+ size_t sz;
+ int err;
+} qpol_fbuf_t;
+
+static void qpol_handle_route_to_callback(void *varg
+ __attribute__ ((unused)), const qpol_policy_t * p, int level, const char *fmt,
+ va_list va_args)
+{
+ if (!p || !(p->fn)) {
+ vfprintf(stderr, fmt, va_args);
+ fprintf(stderr, "\n");
+ return;
+ }
+
+ p->fn(p->varg, p, level, fmt, va_args);
+}
+
+static void sepol_handle_route_to_callback(void *varg, sepol_handle_t * sh, const char *fmt, ...)
+{
+ va_list ap;
+ qpol_policy_t *p = varg;
+
+ if (!sh) {
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+ return;
+ }
+
+ va_start(ap, fmt);
+ qpol_handle_route_to_callback(NULL, p, sepol_msg_get_level(sh), fmt, ap);
+ va_end(ap);
+}
+
+void qpol_handle_msg(const qpol_policy_t * p, int level, const char *fmt, ...)
+{
+ va_list ap;
+
+ if (!p) {
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+ return;
+ }
+
+ va_start(ap, fmt);
+ /* explicit cast here to remove const for sepol handle */
+ qpol_handle_route_to_callback((void *)p->varg, p, level, fmt, ap);
+ va_end(ap);
+}
+
+static void qpol_handle_default_callback(void *varg __attribute__ ((unused)), const qpol_policy_t * p
+ __attribute__ ((unused)), int level, const char *fmt, va_list va_args)
+{
+ switch (level) {
+ case QPOL_MSG_INFO:
+ {
+ /* by default ignore info messages */
+ return;
+ }
+ case QPOL_MSG_WARN:
+ {
+ fprintf(stderr, "WARNING: ");
+ break;
+ }
+ case QPOL_MSG_ERR:
+ default:
+ {
+ fprintf(stderr, "ERROR: ");
+ break;
+ }
+ }
+
+ vfprintf(stderr, fmt, va_args);
+ fprintf(stderr, "\n");
+}
+
+static int read_source_policy(qpol_policy_t * qpolicy, char *progname, int options)
+{
+ int load_rules = 1;
+ if (options & QPOL_POLICY_OPTION_NO_RULES)
+ load_rules = 0;
+ if ((id_queue = queue_create()) == NULL) {
+ ERR(qpolicy, "%s", strerror(ENOMEM));
+ return -1;
+ }
+
+ policydbp = &qpolicy->p->p;
+ mlspol = policydbp->mls;
+
+ INFO(qpolicy, "%s", "Parsing policy. (Step 1 of 5)");
+ init_scanner();
+ init_parser(1, load_rules);
+ errno = 0;
+ if (yyparse() || policydb_errors) {
+ ERR(qpolicy, "%s: error(s) encountered while parsing configuration\n", progname);
+ queue_destroy(id_queue);
+ id_queue = NULL;
+// errno = EIO;
+ return -1;
+ }
+ /* rewind the pointer */
+ qpol_src_inputptr = qpol_src_originalinput;
+ init_parser(2, load_rules);
+ source_file[0] = '\0';
+ if (yyparse() || policydb_errors) {
+ ERR(qpolicy, "%s: error(s) encountered while parsing configuration\n", progname);
+ queue_destroy(id_queue);
+ id_queue = NULL;
+// errno = EIO;
+ return -1;
+ }
+ queue_destroy(id_queue);
+ id_queue = NULL;
+ if (policydb_errors) {
+// errno = EIO;
+ return -1;
+ }
+ return 0;
+}
+
+static int qpol_init_fbuf(qpol_fbuf_t ** fb)
+{
+ if (fb == NULL)
+ return -1;
+ *fb = (qpol_fbuf_t *) malloc(sizeof(qpol_fbuf_t));
+ if (*fb == NULL)
+ return -1;
+ (*fb)->buf = NULL;
+ (*fb)->sz = 0;
+ (*fb)->err = 0;
+ return 0;
+}
+
+static void qpol_free_fbuf(qpol_fbuf_t ** fb)
+{
+ if (*fb == NULL)
+ return;
+ if ((*fb)->sz > 0 && (*fb)->buf != NULL)
+ free((*fb)->buf);
+ free(*fb);
+ return;
+}
+
+static void *qpol_read_fbuf(qpol_fbuf_t * fb, size_t bytes, FILE * fp)
+{
+ size_t sz;
+
+ assert(fb != NULL && fp != NULL);
+ assert(!(fb->sz > 0 && fb->buf == NULL));
+
+ if (fb->sz == 0) {
+ fb->buf = (char *)malloc(bytes + 1);
+ fb->sz = bytes + 1;
+ } else if (bytes + 1 > fb->sz) {
+ fb->buf = (char *)realloc(fb->buf, bytes + 1);
+ fb->sz = bytes + 1;
+ }
+
+ if (fb->buf == NULL) {
+ fb->err = -1;
+ return NULL;
+ }
+
+ sz = fread(fb->buf, bytes, 1, fp);
+ if (sz != 1) {
+ fb->err = -3;
+ return NULL;
+ }
+ fb->err = 0;
+ return fb->buf;
+}
+
+int qpol_binpol_version(FILE * fp)
+{
+ __u32 *buf;
+ int rt, len;
+ qpol_fbuf_t *fb;
+
+ if (fp == NULL)
+ return -1;
+
+ if (qpol_init_fbuf(&fb) != 0)
+ return -1;
+
+ /* magic # and sz of policy string */
+ buf = qpol_read_fbuf(fb, sizeof(__u32) * 2, fp);
+ if (buf == NULL) {
+ rt = fb->err;
+ goto err_return;
+ }
+ buf[0] = le32_to_cpu(buf[0]);
+ if (buf[0] != SELINUX_MAGIC) {
+ rt = -2;
+ goto err_return;
+ }
+
+ len = le32_to_cpu(buf[1]);
+ if (len < 0) {
+ rt = -3;
+ goto err_return;
+ }
+ /* skip over the policy string */
+ if (fseek(fp, sizeof(char) * len, SEEK_CUR) != 0) {
+ rt = -3;
+ goto err_return;
+ }
+
+ /* Read the version, config, and table sizes. */
+ buf = qpol_read_fbuf(fb, sizeof(__u32) * 1, fp);
+ if (buf == NULL) {
+ rt = fb->err;
+ goto err_return;
+ }
+ buf[0] = le32_to_cpu(buf[0]);
+
+ rt = buf[0];
+ err_return:
+ rewind(fp);
+ qpol_free_fbuf(&fb);
+ return rt;
+}
+
+int qpol_is_file_binpol(FILE * fp)
+{
+ int rt;
+ size_t sz;
+ __u32 ubuf;
+
+ sz = fread(&ubuf, sizeof(__u32), 1, fp);
+ if (sz != 1)
+ rt = 0;
+
+ ubuf = le32_to_cpu(ubuf);
+ if (ubuf == SELINUX_MAGIC)
+ rt = 1;
+ else
+ rt = 0;
+ rewind(fp);
+ return rt;
+}
+
+int qpol_is_data_mod_pkg(char * data)
+{
+ size_t sz;
+ __u32 ubuf;
+
+ memcpy(&ubuf, data, sizeof(__u32));
+
+ ubuf = le32_to_cpu(ubuf);
+ if (ubuf == SEPOL_MODULE_PACKAGE_MAGIC)
+ return 1;
+
+ return 0;
+}
+
+int qpol_is_file_mod_pkg(FILE * fp)
+{
+ size_t sz;
+ __u32 ubuf;
+ int rt;
+
+ sz = fread(&ubuf, sizeof(__u32), 1, fp);
+
+ if (sz != 1)
+ rt = 0; /* problem reading file */
+
+ ubuf = le32_to_cpu(ubuf);
+ if (ubuf == SEPOL_MODULE_PACKAGE_MAGIC)
+ rt = 1;
+ else
+ rt = 0;
+ rewind(fp);
+ return rt;
+}
+
+static int infer_policy_version(qpol_policy_t * policy)
+{
+ policydb_t *db = NULL;
+ const qpol_class_t *obj_class = NULL;
+ qpol_iterator_t *iter = NULL;
+ qpol_fs_use_t *fsuse = NULL;
+ qpol_range_trans_t *rangetrans = NULL;
+ uint32_t behavior = 0;
+ size_t nvtrans = 0, fsusexattr = 0;
+ const char *obj_name = NULL;
+
+ if (!policy) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+
+ if (db->policyvers) {
+ /* version already set */
+ return STATUS_SUCCESS;
+ }
+
+ /* check fs_use for xattr and psid */
+ qpol_policy_get_fs_use_iter(policy, &iter);
+ for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
+ qpol_iterator_get_item(iter, (void **)&fsuse);
+ qpol_fs_use_get_behavior(policy, fsuse, &behavior);
+ /* not possible to have xattr and psid in same policy */
+ if (behavior == QPOL_FS_USE_XATTR) {
+ fsusexattr = 1;
+ break;
+ } else if (behavior == QPOL_FS_USE_PSID) {
+ qpol_iterator_destroy(&iter);
+ db->policyvers = 12;
+ return STATUS_SUCCESS;
+ }
+ }
+ qpol_iterator_destroy(&iter);
+
+#if defined(HAVE_SEPOL_PERMISSIVE_TYPES) || defined(HAVE_SEPOL_POLICYCAPS)
+ ebitmap_node_t *node = NULL;
+ unsigned int i = 0;
+#endif
+
+ /* 23 : there exists at least one type that is permissive */
+#ifdef HAVE_SEPOL_PERMISSIVE_TYPES
+ ebitmap_for_each_bit(&db->permissive_map, node, i) {
+ if (ebitmap_get_bit(&db->permissive_map, i)) {
+ db->policyvers = 23;
+ return STATUS_SUCCESS;
+ }
+ }
+#endif
+
+ /* 22 : there exists at least one policy capability */
+#ifdef HAVE_SEPOL_POLICYCAPS
+ ebitmap_for_each_bit(&db->policycaps, node, i) {
+ if (ebitmap_get_bit(&db->policycaps, i)) {
+ db->policyvers = 22;
+ return STATUS_SUCCESS;
+ }
+ }
+#endif
+
+ /* 21 : object classes other than process for range_transitions */
+ qpol_policy_get_range_trans_iter(policy, &iter);
+ for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
+ qpol_iterator_get_item(iter, (void **)&rangetrans);
+ qpol_range_trans_get_target_class(policy, rangetrans, &obj_class);
+ qpol_class_get_name(policy, obj_class, &obj_name);
+ if (strcmp(obj_name, "process")) {
+ db->policyvers = 21;
+ qpol_iterator_destroy(&iter);
+ return STATUS_SUCCESS;
+ }
+ }
+ qpol_iterator_destroy(&iter);
+
+ /* 19 & 20 : mls and validatetrans statements added */
+ qpol_policy_get_validatetrans_iter(policy, &iter);
+ qpol_iterator_get_size(iter, &nvtrans);
+ qpol_iterator_destroy(&iter);
+ if (db->mls || nvtrans) {
+ db->policyvers = 19;
+ }
+
+ /* 18 : the netlink_audit_socket class added */
+ else if (hashtab_search(db->p_classes.table, (const hashtab_key_t)"netlink_audit_socket")) {
+ db->policyvers = 18;
+ }
+
+ /* 17 : IPv6 nodecon statements added */
+ else if (db->ocontexts[OCON_NODE6]) {
+ db->policyvers = 17;
+ }
+
+ /* 16 : conditional policy added */
+ else if (db->p_bool_val_to_name && db->p_bool_val_to_name[0]) {
+ db->policyvers = 16;
+
+ }
+ /* 15 */
+ else if (fsusexattr) {
+ db->policyvers = 15;
+ }
+
+ /* 12 */
+ else {
+ db->policyvers = 12;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+/** State tracking struct used in the functions check_disabled, remove_symbol, and prune_disabled_symbols to handle disabled symbols */
+struct symbol_pruning_state
+{
+ qpol_policy_t *p; /**< The policy */
+ int symbol_type; /**< The current symbol type being processed */
+};
+
+/** Apply callback for hashtab_map_remove_on_error.
+ * This function tests whether a symbol referenced by the policy is declared or only ever required.
+ * Symbols without a declaration are disabled and must be removed.
+ * @param key Symbol key to check.
+ * @param datum Symbol datum to check.
+ * @param args State object (of type struct symbol_pruning_state)
+ * @return 0 if symbol is enabled, 1 if not enabled.
+ */
+static int check_disabled(hashtab_key_t key, hashtab_datum_t datum, void *args)
+{
+ struct symbol_pruning_state *s = args;
+ if (!is_id_enabled((char *)key, &(s->p->p->p), s->symbol_type))
+ return 1;
+ return 0;
+}
+
+/** Remove callback for hashtab_map_remove_on_error.
+ * Frees all memory associated with a disabled symbol that has been removed from the symbol table.
+ * @param key Symbol key to remove
+ * @param datum Symbol datum to remove
+ * @param args State object (of type struct symbol_pruning_state)
+ * @post All memory associated with the symbol is freed.
+ */
+static void remove_symbol(hashtab_key_t key, hashtab_datum_t datum, void *args)
+{
+ struct symbol_pruning_state *s = args;
+ switch (s->symbol_type) {
+ case SYM_ROLES:
+ {
+ role_datum_destroy((role_datum_t *) datum);
+ break;
+ }
+ case SYM_TYPES:
+ {
+ type_datum_destroy((type_datum_t *) datum);
+ break;
+ }
+ case SYM_USERS:
+ {
+ user_datum_destroy((user_datum_t *) datum);
+ break;
+ }
+ case SYM_BOOLS:
+ {
+ /* no-op */
+ break;
+ }
+ case SYM_LEVELS:
+ {
+ level_datum_destroy((level_datum_t *) datum);
+ break;
+ }
+ case SYM_CATS:
+ {
+ cat_datum_destroy((cat_datum_t *) datum);
+ break;
+ }
+ default:
+ return; /* invalid type of datum to free; do nothing */
+ }
+ free(key);
+ free(datum);
+}
+
+/** Remove symbols that are only required but never declared from the policy.
+ * Removes each disabled symbol freeing all memory associated with it.
+ * @param policy The policy from which disabled symbols should be removed.
+ * @return always 0.
+ * @note Since hashtab_map_remove_on_error does not return any error status,
+ * it is impossible to tell if it has failed; if it fails, the policy will
+ * be in an inconsistent state.
+ */
+static int prune_disabled_symbols(qpol_policy_t * policy)
+{
+ if (policy->type == QPOL_POLICY_KERNEL_BINARY)
+ return 0; /* checkpolicy already prunes disabled symbols */
+ struct symbol_pruning_state state;
+ state.p = policy;
+ for (state.symbol_type = SYM_ROLES; state.symbol_type < SYM_NUM; state.symbol_type++) {
+ hashtab_map_remove_on_error(policy->p->p.symtab[state.symbol_type].table, check_disabled, remove_symbol, &state);
+ }
+ return 0;
+}
+
+/** For all symbols that are multiply defined (such as attributes, roles, and users),
+ * union the relevant sets of types and roles from each declaration.
+ * @param policy The policy containig the symbols to union.
+ * @return 0 on success, non-zero on error; if the call fails,
+ * errno will be set, and the policy should be considered invalid.
+ */
+static int union_multiply_declared_symbols(qpol_policy_t * policy) {
+ /* general structure of this function:
+ walk role and user symbol tables for each role/user/attribute
+ get datum from symtab, get key from array
+ look up symbol in scope table
+ foreach decl_id in scope entry
+ union types/roles bitmap with datum's copy
+ */
+ qpol_iterator_t * iter = NULL;
+ int error = 0;
+ if (qpol_policy_get_type_iter(policy, &iter)) {
+ return 1;
+ }
+ for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
+ type_datum_t *attr;
+ if (qpol_iterator_get_item(iter, (void**)&attr)) {
+ error = errno;
+ goto err;
+ }
+ unsigned char isattr = 0;
+ if (qpol_type_get_isattr(policy, attr, &isattr)) {
+ error = errno;
+ goto err;
+ }
+ if (!isattr)
+ continue;
+ const char *name;
+ if (qpol_type_get_name(policy, (qpol_type_t*)attr, &name)) {
+ error = errno;
+ goto err;
+ }
+ policydb_t *db = &policy->p->p;
+ avrule_block_t *blk = db->global;
+ for (; blk; blk = blk->next) {
+ avrule_decl_t *decl = blk->enabled;
+ if (!decl)
+ continue; /* disabled */
+ type_datum_t *internal_datum = hashtab_search(decl->symtab[SYM_TYPES].table, (const hashtab_key_t)name);
+ if (internal_datum == NULL) {
+ continue; /* not declared here */
+ }
+ if (ebitmap_union(&attr->types, &internal_datum->types))
+ {
+ error = errno;
+ ERR(policy, "could not merge declarations for attribute %s", name);
+ goto err;
+ }
+ }
+ }
+ qpol_iterator_destroy(&iter);
+
+ /* repeat for roles */
+ if (qpol_policy_get_role_iter(policy, &iter)) {
+ return 1;
+ }
+ for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
+ role_datum_t *role;
+ if (qpol_iterator_get_item(iter, (void**)&role)) {
+ error = errno;
+ goto err;
+ }
+ const char *name;
+ if (qpol_role_get_name(policy, (qpol_role_t*)role, &name)) {
+ error = errno;
+ goto err;
+ }
+ policydb_t *db = &policy->p->p;
+ scope_datum_t* scope_datum = hashtab_search(db->scope[SYM_ROLES].table, (const hashtab_key_t)name);
+ if (scope_datum == NULL) {
+ ERR(policy, "could not find scope datum for role %s", name);
+ error = ENOENT;
+ goto err;
+ }
+ for (uint32_t i = 0; i < scope_datum->decl_ids_len; i++)
+ {
+ if (db->decl_val_to_struct[scope_datum->decl_ids[i] - 1]->enabled == 0)
+ continue; /* block is disabled */
+ role_datum_t *internal_datum = hashtab_search(db->decl_val_to_struct[scope_datum->decl_ids[i] - 1]->symtab[SYM_ROLES].table, (const hashtab_key_t)name);
+ if (internal_datum == NULL) {
+ continue; /* not declared here */
+ }
+ if (ebitmap_union(&role->types.types, &internal_datum->types.types) || ebitmap_union(&role->dominates, &internal_datum->dominates))
+ {
+ error = errno;
+ ERR(policy, "could not merge declarations for role %s", name);
+ goto err;
+ }
+ }
+ }
+ qpol_iterator_destroy(&iter);
+
+ /* repeat for users */
+ if (qpol_policy_get_user_iter(policy, &iter)) {
+ return 1;
+ }
+ for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
+ user_datum_t *user;
+ if (qpol_iterator_get_item(iter, (void**)&user)) {
+ error = errno;
+ goto err;
+ }
+ const char *name;
+ if (qpol_user_get_name(policy, (qpol_user_t*)user, &name)) {
+ error = errno;
+ goto err;
+ }
+ policydb_t *db = &policy->p->p;
+ scope_datum_t* scope_datum = hashtab_search(db->scope[SYM_USERS].table, (const hashtab_key_t)name);
+ if (scope_datum == NULL) {
+ ERR(policy, "could not find scope datum for user %s", name);
+ error = ENOENT;
+ goto err;
+ }
+ for (uint32_t i = 0; i < scope_datum->decl_ids_len; i++)
+ {
+ if (db->decl_val_to_struct[scope_datum->decl_ids[i] - 1]->enabled == 0)
+ continue; /* block is disabled */
+ user_datum_t *internal_datum = hashtab_search(db->decl_val_to_struct[scope_datum->decl_ids[i] -1 ]->symtab[SYM_USERS].table, (const hashtab_key_t)name);
+ if (internal_datum == NULL) {
+ continue; /* not declared here */
+ }
+ if (ebitmap_union(&user->roles.roles, &internal_datum->roles.roles))
+ {
+ error = errno;
+ ERR(policy, "could not merge declarations for user %s", name);
+ goto err;
+ }
+ }
+ }
+ qpol_iterator_destroy(&iter);
+
+ return 0;
+err:
+ qpol_iterator_destroy(&iter);
+ errno = error;
+ return 1;
+}
+
+/* forward declarations see policy_extend.c */
+struct qpol_extended_image;
+extern void qpol_extended_image_destroy(struct qpol_extended_image **ext);
+
+#if LINK_SHARED == 1
+__asm__(".symver qpol_policy_open_from_file_old,qpol_policy_open_from_file@");
+__asm__(".symver qpol_policy_open_from_file_opt,qpol_policy_open_from_file@@VERS_1.3");
+__asm__(".symver qpol_policy_open_from_memory_old,qpol_policy_open_from_memory@");
+__asm__(".symver qpol_policy_open_from_memory_opt,qpol_policy_open_from_memory@VERS_1.3");
+__asm__(".symver qpol_policy_rebuild_old,qpol_policy_rebuild@");
+__asm__(".symver qpol_policy_rebuild_opt,qpol_policy_rebuild@@VERS_1.3");
+#endif
+
+/**
+ * @brief Internal version of qpol_policy_rebuild() version 1.3
+ *
+ * Implementation of the exported function qpol_policy_rebuild()
+ * for version 1.3; this symbol name is not exported.
+ * @see qpol_policy_rebuild()
+ */
+int qpol_policy_rebuild_opt(qpol_policy_t * policy, const int options)
+{
+ sepol_policydb_t *old_p = NULL;
+ sepol_policydb_t **modules = NULL;
+ qpol_module_t *base = NULL;
+ size_t num_modules = 0, i;
+ int error = 0, old_options;
+
+ if (!policy) {
+ ERR(NULL, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ /* if kernel binary do nothing */
+ if (policy->type == QPOL_POLICY_KERNEL_BINARY)
+ return STATUS_SUCCESS;
+
+ /* if options are the same and the modules were not modified, do nothing */
+ if (options == policy->options && policy->modified == 0)
+ return STATUS_SUCCESS;
+
+ /* cache old policy in case of failure */
+ old_p = policy->p;
+ policy->p = NULL;
+ struct qpol_extended_image *ext = policy->ext;
+ policy->ext = NULL;
+ old_options = policy->options;
+ policy->options = options;
+
+ /* QPOL_POLICY_OPTION_NO_RULES implies QPOL_POLICY_OPTION_NO_NEVERALLOWS */
+ if (policy->options & QPOL_POLICY_OPTION_NO_RULES)
+ policy->options |= QPOL_POLICY_OPTION_NO_NEVERALLOWS;
+
+ if (policy->type == QPOL_POLICY_MODULE_BINARY) {
+ /* allocate enough space for all modules then fill with list of enabled ones only */
+ if (!(modules = calloc(policy->num_modules, sizeof(sepol_policydb_t *)))) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto err;
+ }
+ /* first module is base and cannot be disabled */
+ for (i = 1; i < policy->num_modules; i++) {
+ if ((policy->modules[i])->enabled) {
+ modules[num_modules++] = (policy->modules[i])->p;
+ }
+ }
+ /* have to reopen the base since link alters it */
+ if (qpol_module_create_from_file((policy->modules[0])->path, &base)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto err;
+ }
+ /* take the policy from base and use as new base into which to link */
+ policy->p = base->p;
+ base->p = NULL;
+ qpol_module_destroy(&base);
+ if (sepol_link_modules(policy->sh, policy->p, modules, num_modules, 0)) {
+ error = EIO;
+ goto err;
+ }
+ free(modules);
+ } else {
+ /* repeat open process as if qpol_policy_open_from_memory() */
+ if (sepol_policydb_create(&(policy->p))) {
+ error = errno;
+ goto err;
+ }
+
+ qpol_src_input = policy->file_data;
+ qpol_src_inputptr = qpol_src_input;
+ qpol_src_inputlim = qpol_src_inputptr + policy->file_data_sz - 1;
+ qpol_src_originalinput = qpol_src_input;
+
+ /* read in source */
+ policy->p->p.policy_type = POLICY_BASE;
+ if (read_source_policy(policy, "parse", policy->options) < 0) {
+ error = errno;
+ goto err;
+ }
+
+ /* link the source */
+ INFO(policy, "%s", "Linking source policy. (Step 2 of 5)");
+ if (sepol_link_modules(policy->sh, policy->p, NULL, 0, 0)) {
+ error = EIO;
+ goto err;
+ }
+ avtab_destroy(&(policy->p->p.te_avtab));
+ avtab_destroy(&(policy->p->p.te_cond_avtab));
+ avtab_init(&(policy->p->p.te_avtab));
+ avtab_init(&(policy->p->p.te_cond_avtab));
+ }
+
+ if (prune_disabled_symbols(policy)) {
+ error = errno;
+ goto err;
+ }
+
+ if (union_multiply_declared_symbols(policy)) {
+ error = errno;
+ goto err;
+ }
+
+ if (qpol_expand_module(policy, !(policy->options & (QPOL_POLICY_OPTION_NO_NEVERALLOWS)))) {
+ error = errno;
+ goto err;
+ }
+
+ if (infer_policy_version(policy)) {
+ error = errno;
+ goto err;
+ }
+
+ if (policy_extend(policy)) {
+ error = errno;
+ goto err;
+ }
+ qpol_extended_image_destroy(&ext);
+
+ sepol_policydb_free(old_p);
+
+ return STATUS_SUCCESS;
+
+ err:
+ free(modules);
+
+ policy->p = old_p;
+ policy->ext = ext;
+ policy->options = old_options;
+ errno = error;
+ return STATUS_ERR;
+}
+
+#if LINK_SHARED == 0
+int qpol_policy_rebuild(qpol_policy_t * policy, int options)
+{
+ return qpol_policy_rebuild_opt(policy, options);
+}
+#endif
+
+/**
+ * @brief Internal version of qpol_policy_rebuild() version 1.2 or earlier
+ * @deprecated use the 1.3 version.
+ * @see qpol_policy_rebuild()
+ */
+int qpol_policy_rebuild_old(qpol_policy_t * policy)
+{
+ if (!policy) {
+ ERR(NULL, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ /* fail if not a modular policy */
+ if (policy->type != QPOL_POLICY_MODULE_BINARY) {
+ ERR(policy, "%s", strerror(ENOTSUP));
+ errno = ENOTSUP;
+ return STATUS_ERR;
+ }
+
+ if (!policy->modified)
+ return STATUS_SUCCESS;
+
+ return qpol_policy_rebuild_opt(policy, policy->options);
+}
+
+/**
+ * @brief Internal version of qpol_policy_open_from_file() version 1.3
+ *
+ * Implementation of the exported function qpol_policy_open_from_file()
+ * for version 1.3; this symbol name is not exported.
+ * @see qpol_policy_open_from_file()
+ */
+int qpol_policy_open_from_file_opt(const char *path, qpol_policy_t ** policy, qpol_callback_fn_t fn, void *varg, const int options)
+{
+ int error = 0, retv = -1;
+ FILE *infile = NULL;
+ sepol_policy_file_t *pfile = NULL;
+ qpol_module_t *mod = NULL;
+ int fd = 0;
+ struct stat sb;
+
+ if (policy != NULL)
+ *policy = NULL;
+
+ if (path == NULL || policy == NULL) {
+ /* handle passed as NULL here as it has yet to be created */
+ ERR(NULL, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return -1;
+ }
+
+ errno = 0;
+ if (!(*policy = calloc(1, sizeof(qpol_policy_t)))) {
+ error = errno;
+ ERR(NULL, "%s", strerror(error));
+ goto err;
+ }
+ (*policy)->options = options;
+
+ /* QPOL_POLICY_OPTION_NO_RULES implies QPOL_POLICY_OPTION_NO_NEVERALLOWS */
+ if ((*policy)->options & QPOL_POLICY_OPTION_NO_RULES)
+ (*policy)->options |= QPOL_POLICY_OPTION_NO_NEVERALLOWS;
+
+ (*policy)->sh = sepol_handle_create();
+ if ((*policy)->sh == NULL) {
+ error = errno;
+ ERR(*policy, "%s", strerror(error));
+ errno = error;
+ return -1;
+ }
+
+ if (fn) {
+ (*policy)->fn = fn;
+ (*policy)->varg = varg;
+ } else {
+ (*policy)->fn = qpol_handle_default_callback;
+ }
+ sepol_msg_set_callback((*policy)->sh, sepol_handle_route_to_callback, (*policy));
+
+ if (sepol_policydb_create(&((*policy)->p))) {
+ error = errno;
+ goto err;
+ }
+
+ if (sepol_policy_file_create(&pfile)) {
+ error = errno;
+ goto err;
+ }
+
+ infile = fopen(path, "rb");
+ if (infile == NULL) {
+ error = errno;
+ goto err;
+ }
+
+ sepol_policy_file_set_handle(pfile, (*policy)->sh);
+
+ errno=0;
+ if (qpol_is_file_binpol(infile)) {
+ (*policy)->type = retv = QPOL_POLICY_KERNEL_BINARY;
+ sepol_policy_file_set_fp(pfile, infile);
+ if (sepol_policydb_read((*policy)->p, pfile)) {
+// error = EIO;
+ goto err;
+ }
+ /* By definition, binary policy cannot have neverallow rules and all other rules are always loaded. */
+ (*policy)->options |= QPOL_POLICY_OPTION_NO_NEVERALLOWS;
+ (*policy)->options &= ~(QPOL_POLICY_OPTION_NO_RULES);
+ if (policy_extend(*policy)) {
+ error = errno;
+ goto err;
+ }
+ } else if (qpol_module_create_from_file(path, &mod) == STATUS_SUCCESS) {
+ (*policy)->type = retv = QPOL_POLICY_MODULE_BINARY;
+
+ if (qpol_policy_append_module(*policy, mod)) {
+ error = errno;
+ goto err;
+ }
+ /* *policy now owns mod */
+ mod = NULL;
+ if (qpol_policy_rebuild_opt(*policy, options)) {
+ error = errno;
+ goto err;
+ }
+ } else {
+ (*policy)->type = retv = QPOL_POLICY_KERNEL_SOURCE;
+ fd = fileno(infile);
+ if (fd < 0) {
+ error = errno;
+ goto err;
+ }
+ if (fstat(fd, &sb) < 0) {
+ error = errno;
+ ERR(*policy, "Can't stat '%s': %s\n", path, strerror(errno));
+ goto err;
+ }
+ qpol_src_input = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (qpol_src_input == MAP_FAILED) {
+ error = errno;
+ ERR(*policy, "Can't map '%s': %s\n", path, strerror(errno));
+
+ goto err;
+ }
+ qpol_src_inputptr = qpol_src_input;
+ qpol_src_inputlim = &qpol_src_inputptr[sb.st_size - 1];
+ qpol_src_originalinput = qpol_src_input;
+
+ /* store mmaped version for rebuild() */
+ (*policy)->file_data = qpol_src_originalinput;
+ (*policy)->file_data_sz = sb.st_size;
+ (*policy)->file_data_type = QPOL_POLICY_FILE_DATA_TYPE_MMAP;
+
+ (*policy)->p->p.policy_type = POLICY_BASE;
+ if (read_source_policy(*policy, "libqpol", (*policy)->options) < 0) {
+ error = errno;
+ goto err;
+ }
+
+ /* link the source */
+ INFO(*policy, "%s", "Linking source policy. (Step 2 of 5)");
+ if (sepol_link_modules((*policy)->sh, (*policy)->p, NULL, 0, 0)) {
+ error = EIO;
+ goto err;
+ }
+ avtab_destroy(&((*policy)->p->p.te_avtab));
+ avtab_destroy(&((*policy)->p->p.te_cond_avtab));
+ avtab_init(&((*policy)->p->p.te_avtab));
+ avtab_init(&((*policy)->p->p.te_cond_avtab));
+
+ if (prune_disabled_symbols(*policy)) {
+ error = errno;
+ goto err;
+ }
+
+ if (union_multiply_declared_symbols(*policy)) {
+ error = errno;
+ goto err;
+ }
+
+ /* expand */
+ if (qpol_expand_module(*policy, !(options & (QPOL_POLICY_OPTION_NO_NEVERALLOWS)))) {
+ error = errno;
+ goto err;
+ }
+
+ if (infer_policy_version(*policy)) {
+ error = errno;
+ goto err;
+ }
+ if (policy_extend(*policy)) {
+ error = errno;
+ goto err;
+ }
+ }
+
+ fclose(infile);
+ sepol_policy_file_free(pfile);
+ return retv;
+
+ err:
+ qpol_policy_destroy(policy);
+ qpol_module_destroy(&mod);
+ sepol_policy_file_free(pfile);
+ if (infile)
+ fclose(infile);
+ errno = error;
+ return -1;
+}
+
+#if LINK_SHARED == 0
+int qpol_policy_open_from_file(const char *path, qpol_policy_t ** policy, qpol_callback_fn_t fn, void *varg, const int options)
+{
+ return qpol_policy_open_from_file_opt(path, policy, fn, varg, options);
+}
+#endif
+
+int qpol_policy_open_from_file_no_rules(const char *path, qpol_policy_t ** policy, qpol_callback_fn_t fn, void *varg)
+{
+ return qpol_policy_open_from_file_opt(path, policy, fn, varg, QPOL_POLICY_OPTION_NO_RULES);
+}
+
+/**
+ * @brief Internal version of qpol_policy_open_from_memory() version 1.3
+ *
+ * Implementation of the exported function qpol_policy_open_from_memory()
+ * for version 1.3; this symbol name is not exported.
+ * @see qpol_policy_open_from_memory()
+ */
+int qpol_policy_open_from_memory_opt(qpol_policy_t ** policy, const char *filedata, size_t size, qpol_callback_fn_t fn, void *varg,
+ const int options)
+{
+ int error = 0;
+ if (policy == NULL || filedata == NULL)
+ return -1;
+ *policy = NULL;
+
+ if (!(*policy = calloc(1, sizeof(qpol_policy_t)))) {
+ error = errno;
+ goto err;
+ }
+ (*policy)->options = options;
+
+ /* QPOL_POLICY_OPTION_NO_RULES implies QPOL_POLICY_OPTION_NO_NEVERALLOWS */
+ if ((*policy)->options & QPOL_POLICY_OPTION_NO_RULES)
+ (*policy)->options |= QPOL_POLICY_OPTION_NO_NEVERALLOWS;
+
+ (*policy)->sh = sepol_handle_create();
+ if ((*policy)->sh == NULL) {
+ error = errno;
+ ERR(*policy, "%s", strerror(error));
+ errno = error;
+ return -1;
+ }
+
+ sepol_msg_set_callback((*policy)->sh, sepol_handle_route_to_callback, (*policy));
+ if (fn) {
+ (*policy)->fn = fn;
+ (*policy)->varg = varg;
+ } else {
+ (*policy)->fn = qpol_handle_default_callback;
+ }
+
+ if (sepol_policydb_create(&((*policy)->p))) {
+ error = errno;
+ goto err;
+ }
+
+ qpol_src_input = (char *)filedata;
+ qpol_src_inputptr = qpol_src_input;
+ qpol_src_inputlim = qpol_src_inputptr + size - 1;
+ qpol_src_originalinput = qpol_src_input;
+
+ /* store filedata for rebuild() */
+ if (!((*policy)->file_data = malloc(size))) {
+ error = errno;
+ goto err;
+ }
+ memcpy((*policy)->file_data, filedata, size);
+ (*policy)->file_data_sz = size;
+ (*policy)->file_data_type = QPOL_POLICY_FILE_DATA_TYPE_MEM;
+
+ /* read in source */
+ (*policy)->p->p.policy_type = POLICY_BASE;
+ if (read_source_policy(*policy, "parse", (*policy)->options) < 0)
+ exit(1);
+
+ /* link the source */
+ INFO(*policy, "%s", "Linking source policy. (Step 2 of 5)");
+ if (sepol_link_modules((*policy)->sh, (*policy)->p, NULL, 0, 0)) {
+ error = EIO;
+ goto err;
+ }
+ avtab_destroy(&((*policy)->p->p.te_avtab));
+ avtab_destroy(&((*policy)->p->p.te_cond_avtab));
+ avtab_init(&((*policy)->p->p.te_avtab));
+ avtab_init(&((*policy)->p->p.te_cond_avtab));
+
+ if (prune_disabled_symbols(*policy)) {
+ error = errno;
+ goto err;
+ }
+
+ if (union_multiply_declared_symbols(*policy)) {
+ error = errno;
+ goto err;
+ }
+
+ /* expand */
+ if (qpol_expand_module(*policy, !(options & (QPOL_POLICY_OPTION_NO_NEVERALLOWS)))) {
+ error = errno;
+ goto err;
+ }
+
+ return 0;
+ err:
+ qpol_policy_destroy(policy);
+ errno = error;
+ return -1;
+
+}
+
+#if LINK_SHARED == 0
+int qpol_policy_open_from_memory(qpol_policy_t ** policy, const char *filedata, size_t size, qpol_callback_fn_t fn, void *varg,
+ const int options)
+{
+ return qpol_policy_open_from_memory_opt(policy, filedata, size, fn, varg, options);
+}
+#endif
+
+/**
+ * @brief Internal version of qpol_policy_open_from_file() version 1.2 or earlier
+ * @deprecated use the 1.3 version.
+ * @see qpol_policy_open_from_file()
+ */
+int qpol_policy_open_from_file_old(const char *path, qpol_policy_t ** policy, qpol_callback_fn_t fn, void *varg)
+{
+ return qpol_policy_open_from_file(path, policy, fn, varg, 0);
+}
+
+/**
+ * @brief Internal version of qpol_policy_open_from_memory() version 1.2 or earlier
+ * @deprecated use the 1.3 version.
+ * @see qpol_policy_open_from_memory()
+ */
+int qpol_policy_open_from_memory_old(qpol_policy_t ** policy, const char *filedata, size_t size, qpol_callback_fn_t fn, void *varg)
+{
+ return qpol_policy_open_from_memory_opt(policy, filedata, size, fn, varg, 0);
+}
+
+void qpol_policy_destroy(qpol_policy_t ** policy)
+{
+ if (policy != NULL && *policy != NULL) {
+ sepol_policydb_free((*policy)->p);
+ sepol_handle_destroy((*policy)->sh);
+ qpol_extended_image_destroy(&((*policy)->ext));
+ if ((*policy)->modules) {
+ size_t i = 0;
+ for (i = 0; i < (*policy)->num_modules; i++) {
+ qpol_module_destroy(&((*policy)->modules[i]));
+ }
+ free((*policy)->modules);
+ }
+ if ((*policy)->file_data_type == QPOL_POLICY_FILE_DATA_TYPE_MEM) {
+ free((*policy)->file_data);
+ } else if ((*policy)->file_data_type == QPOL_POLICY_FILE_DATA_TYPE_MMAP) {
+ munmap((*policy)->file_data, (*policy)->file_data_sz);
+ }
+ free(*policy);
+ *policy = NULL;
+ }
+}
+
+int qpol_policy_reevaluate_conds(qpol_policy_t * policy)
+{
+ policydb_t *db = NULL;
+ cond_node_t *cond = NULL;
+ cond_av_list_t *list_ptr = NULL;
+
+ if (!policy) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+
+ for (cond = db->cond_list; cond; cond = cond->next) {
+ /* evaluate cond */
+ cond->cur_state = cond_evaluate_expr(db, cond->expr);
+ if (cond->cur_state < 0) {
+ ERR(policy, "Error evaluating conditional: %s", strerror(EILSEQ));
+ errno = EILSEQ;
+ return STATUS_ERR;
+ }
+
+ /* walk true list */
+ for (list_ptr = cond->true_list; list_ptr; list_ptr = list_ptr->next) {
+ /* field not used (except by write),
+ * now storing list and enabled flags */
+ if (cond->cur_state)
+ list_ptr->node->merged |= QPOL_COND_RULE_ENABLED;
+ else
+ list_ptr->node->merged &= ~(QPOL_COND_RULE_ENABLED);
+ }
+
+ /* walk false list */
+ for (list_ptr = cond->false_list; list_ptr; list_ptr = list_ptr->next) {
+ /* field not used (except by write),
+ * now storing list and enabled flags */
+ if (!cond->cur_state)
+ list_ptr->node->merged |= QPOL_COND_RULE_ENABLED;
+ else
+ list_ptr->node->merged &= ~(QPOL_COND_RULE_ENABLED);
+ }
+ }
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_policy_append_module(qpol_policy_t * policy, qpol_module_t * module)
+{
+ qpol_module_t **tmp = NULL;
+ int error = 0;
+
+ if (!policy || !module) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ if (!(tmp = realloc(policy->modules, (1 + policy->num_modules) * sizeof(qpol_module_t *)))) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ errno = error;
+ return STATUS_ERR;
+ }
+
+ policy->modules = tmp;
+ policy->modules[policy->num_modules] = module;
+ policy->num_modules++;
+ policy->modified = 1;
+ module->parent = policy;
+
+ return STATUS_SUCCESS;
+}
+
+typedef struct mod_state
+{
+ qpol_module_t **list;
+ size_t cur;
+ size_t end;
+} mod_state_t;
+
+static int mod_state_end(const qpol_iterator_t * iter)
+{
+ mod_state_t *ms;
+
+ if (!iter || !(ms = qpol_iterator_state(iter))) {
+ errno = EINVAL;
+ return 1;
+ }
+
+ return (ms->cur >= ms->end);
+}
+
+static void *mod_state_get_cur(const qpol_iterator_t * iter)
+{
+ mod_state_t *ms;
+
+ if (!iter || !(ms = qpol_iterator_state(iter)) || qpol_iterator_end(iter)) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ return ms->list[ms->cur];
+}
+
+static int mod_state_next(qpol_iterator_t * iter)
+{
+ mod_state_t *ms;
+
+ if (!iter || !(ms = qpol_iterator_state(iter))) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+ if (qpol_iterator_end(iter)) {
+ errno = ERANGE;
+ return STATUS_ERR;
+ }
+
+ ms->cur++;
+
+ return STATUS_SUCCESS;
+}
+
+static size_t mod_state_size(const qpol_iterator_t * iter)
+{
+ mod_state_t *ms;
+
+ if (!iter || !(ms = qpol_iterator_state(iter))) {
+ errno = EINVAL;
+ return 0;
+ }
+
+ return ms->end;
+}
+
+int qpol_policy_get_module_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter)
+{
+ mod_state_t *ms = NULL;
+ int error = 0;
+
+ if (!policy || !iter) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ if (!(ms = calloc(1, sizeof(mod_state_t)))) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ errno = error;
+ return STATUS_ERR;
+ }
+
+ if (qpol_iterator_create(policy, (void *)ms, mod_state_get_cur, mod_state_next, mod_state_end, mod_state_size, free, iter)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ free(ms);
+ errno = error;
+ return STATUS_ERR;
+ }
+
+ ms->end = policy->num_modules;
+ ms->list = policy->modules;
+
+ return STATUS_SUCCESS;
+}
+
+static int is_mls_policy(const qpol_policy_t * policy)
+{
+ policydb_t *db = NULL;
+
+ if (policy == NULL) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+
+ if (db->mls != 0)
+ return 1;
+ else
+ return 0;
+}
+
+int qpol_policy_is_mls_enabled(qpol_policy_t * policy)
+{
+ return is_mls_policy(policy);
+}
+
+int qpol_policy_get_policy_version(const qpol_policy_t * policy, unsigned int *version)
+{
+ policydb_t *db;
+
+ if (version != NULL)
+ *version = 0;
+
+ if (policy == NULL || version == NULL) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+
+ *version = db->policyvers;
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_policy_get_type(const qpol_policy_t * policy, int *type)
+{
+ if (!policy || !type) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ *type = policy->type;
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_policy_has_capability(const qpol_policy_t * policy, qpol_capability_e cap)
+{
+ unsigned int version = 0;
+
+ if (!policy) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return 0;
+ }
+
+ qpol_policy_get_policy_version(policy, &version);
+
+ switch (cap) {
+ case QPOL_CAP_ATTRIB_NAMES:
+ {
+ if ((policy->type == QPOL_POLICY_KERNEL_SOURCE || policy->type == QPOL_POLICY_MODULE_BINARY) || (version >= 24))
+ return 1;
+ break;
+ }
+ case QPOL_CAP_SYN_RULES:
+ {
+ if (policy->type == QPOL_POLICY_KERNEL_SOURCE || policy->type == QPOL_POLICY_MODULE_BINARY)
+ return 1;
+ break;
+ }
+ case QPOL_CAP_LINE_NUMBERS:
+ {
+ if (policy->type == QPOL_POLICY_KERNEL_SOURCE)
+ return 1;
+ break;
+ }
+ case QPOL_CAP_CONDITIONALS:
+ {
+ if (version >= 16 || policy->type == QPOL_POLICY_MODULE_BINARY)
+ return 1;
+ break;
+ }
+ case QPOL_CAP_MLS:
+ {
+ return is_mls_policy(policy);
+ }
+ case QPOL_CAP_MODULES:
+ {
+ if (policy->type == QPOL_POLICY_MODULE_BINARY)
+ return 1;
+ break;
+ }
+ case QPOL_CAP_POLCAPS:
+ {
+ if (version >= 22 && policy->type != QPOL_POLICY_MODULE_BINARY)
+ return 1;
+ if (version >= 7 && policy->type == QPOL_POLICY_MODULE_BINARY)
+ return 1;
+ break;
+ }
+ case QPOL_CAP_RULES_LOADED:
+ {
+ if (!(policy->options & QPOL_POLICY_OPTION_NO_RULES))
+ return 1;
+ break;
+ }
+ case QPOL_CAP_SOURCE:
+ {
+ if (policy->type == QPOL_POLICY_KERNEL_SOURCE)
+ return 1;
+ break;
+ }
+ case QPOL_CAP_NEVERALLOW:
+ {
+ if (!(policy->options & QPOL_POLICY_OPTION_NO_NEVERALLOWS) && policy->type != QPOL_POLICY_KERNEL_BINARY)
+ return 1;
+ break;
+ }
+ default:
+ {
+ ERR(policy, "%s", "Unknown capability");
+ errno = EDOM;
+ break;
+ }
+ }
+ return 0;
+}
diff --git a/libqpol/src/policy_define.c b/libqpol/src/policy_define.c
new file mode 100644
index 0000000..c94f7aa
--- /dev/null
+++ b/libqpol/src/policy_define.c
@@ -0,0 +1,4319 @@
+/**
+ * @file policy_define.c
+ *
+ * This file is based upon checkpolicy/policy_define.c from NSA's SVN
+ * repository. It has been modified to support older policy formats.
+ */
+
+/*
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ */
+
+/*
+ * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
+ *
+ * Support for enhanced MLS infrastructure.
+ *
+ * Updated: David Caplan, <dac@tresys.com>
+ *
+ * Added conditional policy language extensions
+ *
+ * Updated: Joshua Brindle <jbrindle@tresys.com>
+ * Karl MacMillan <kmacmillan@mentalrootkit.com>
+ * Jason Tang <jtang@tresys.com>
+ *
+ * Added support for binary policy modules
+ *
+ * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ * Copyright (C) 2003 - 2008 Tresys Technology, LLC
+ * Copyright (C) 2007 Red Hat Inc.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2.
+ */
+
+/* FLASK */
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <assert.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+
+#include <sepol/policydb/expand.h>
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/services.h>
+#include <sepol/policydb/conditional.h>
+#include <sepol/policydb/flask.h>
+#include <sepol/policydb/hierarchy.h>
+#ifdef HAVE_SEPOL_POLICYCAPS
+#include <sepol/policydb/polcaps.h>
+#endif
+#ifdef HAVE_SEPOL_ERRCODES
+#include <sepol/errcodes.h>
+#endif
+
+#include "queue.h"
+#include <qpol/policy.h>
+#include "module_compiler.h"
+#include "policy_define.h"
+
+policydb_t *policydbp;
+queue_t id_queue = 0;
+unsigned int pass;
+static int load_rules;
+static unsigned int num_rules = 0;
+char *curfile = 0;
+int mlspol = 0;
+
+extern unsigned long policydb_lineno;
+extern unsigned long source_lineno;
+extern unsigned int policydb_errors;
+
+extern int yywarn(char *msg);
+extern int yyerror(char *msg);
+
+#define ERRORMSG_LEN 255
+static char errormsg[ERRORMSG_LEN + 1] = { 0 };
+
+static int id_has_dot(char *id);
+static int parse_security_context(context_struct_t * c);
+
+/* initialize all of the state variables for the scanner/parser */
+void init_parser(int pass_number, int do_rules)
+{
+ policydb_lineno = 1;
+ source_lineno = 1;
+ policydb_errors = 0;
+ pass = pass_number;
+ load_rules = do_rules;
+ num_rules = 0;
+}
+
+void yyerror2(char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vsnprintf(errormsg, ERRORMSG_LEN, fmt, ap);
+ yyerror(errormsg);
+ va_end(ap);
+}
+
+int define_mls(void)
+{
+ mlspol = 1;
+ policydbp->mls = 1;
+
+ return 0;
+}
+
+/* Add a rule onto an avtab hash table only if it does not already
+ * exist. (Note that the avtab is discarded afterwards; it will be
+ * regenerated during expansion.) Return 1 if rule was added (or
+ * otherwise handled successfully), 0 if it conflicted with something,
+ * 2 if the rule is not to be added, or -1 on error.
+ */
+static int insert_check_type_rule(avrule_t * rule, avtab_t * avtab, cond_av_list_t ** list, cond_av_list_t ** other)
+{
+ int ret;
+
+ if (num_rules && !load_rules)
+ return 2;
+
+#ifdef SEPOL_DYNAMIC_AVTAB
+ if (!avtab->htable)
+ if (avtab_alloc(avtab, MAX_AVTAB_SIZE))
+ return -1;
+#endif
+
+ ret = expand_rule(NULL, policydbp, rule, avtab, list, other, 0);
+ if (ret < 0) {
+ yyerror("Failed on expanding rule");
+ }
+ return ret;
+}
+int insert_separator(int push)
+{
+ int error;
+
+ if (push)
+ error = queue_push(id_queue, 0);
+ else
+ error = queue_insert(id_queue, 0);
+
+ if (error) {
+ yyerror("queue overflow");
+ return -1;
+ }
+ return 0;
+}
+
+int insert_id(char *id, int push)
+{
+ char *newid = 0;
+ int error;
+
+ newid = (char *)malloc(strlen(id) + 1);
+ if (!newid) {
+ yyerror("out of memory");
+ return -1;
+ }
+ strcpy(newid, id);
+ if (push)
+ error = queue_push(id_queue, (queue_element_t) newid);
+ else
+ error = queue_insert(id_queue, (queue_element_t) newid);
+
+ if (error) {
+ yyerror("queue overflow");
+ free(newid);
+ return -1;
+ }
+ return 0;
+}
+
+/* If the identifier has a dot within it and that its first character
+ is not a dot then return 1, else return 0. */
+static int id_has_dot(char *id)
+{
+ if (strchr(id, '.') >= id + 1) {
+ return 1;
+ }
+ return 0;
+}
+
+int define_class(void)
+{
+ char *id = 0;
+ class_datum_t *datum = 0;
+ int ret;
+ uint32_t value;
+
+ if (pass == 2) {
+ id = queue_remove(id_queue);
+ free(id);
+ return 0;
+ }
+
+ id = (char *)queue_remove(id_queue);
+ if (!id) {
+ yyerror("no class name for class definition?");
+ return -1;
+ }
+ datum = (class_datum_t *) malloc(sizeof(class_datum_t));
+ if (!datum) {
+ yyerror("out of memory");
+ goto bad;
+ }
+ memset(datum, 0, sizeof(class_datum_t));
+ ret = declare_symbol(SYM_CLASSES, id, datum, &value, &value);
+ switch (ret) {
+ case -3:{
+ yyerror("Out of memory!");
+ goto bad;
+ }
+ case -2:{
+ yyerror2("duplicate declaration of class %s", id);
+ goto bad;
+ }
+ case -1:{
+ yyerror("could not declare class here");
+ goto bad;
+ }
+ case 0:
+ case 1:{
+ break;
+ }
+ default:{
+ assert(0); /* should never get here */
+ }
+ }
+ datum->s.value = value;
+ return 0;
+
+ bad:
+ if (id)
+ free(id);
+ if (datum)
+ free(datum);
+ return -1;
+}
+
+int define_permissive(void)
+{
+ char *type = NULL;
+ struct type_datum *t;
+ int rc = 0;
+
+ type = queue_remove(id_queue);
+
+ if (!type) {
+ yyerror2("forgot to include type in permissive definition?");
+ rc = -1;
+ goto out;
+ }
+
+ if (pass == 1)
+ goto out;
+
+ if (!is_id_in_scope(SYM_TYPES, type)) {
+ yyerror2("type %s is not within scope", type);
+ rc = -1;
+ goto out;
+ }
+
+ t = hashtab_search(policydbp->p_types.table, type);
+ if (!t) {
+ yyerror2("type is not defined: %s", type);
+ rc = -1;
+ goto out;
+ }
+
+ if (t->flavor == TYPE_ATTRIB) {
+ yyerror2("attributes may not be permissive: %s\n", type);
+ rc = -1;
+ goto out;
+ }
+#ifdef HAVE_SEPOL_PERMISSIVE_TYPES
+ t->flags |= TYPE_FLAGS_PERMISSIVE;
+#else
+ yyerror("This version of SETools does not have permissive types enabled.");
+#endif
+ out:
+ free(type);
+ return rc;
+}
+
+int define_polcap(void)
+{
+ char *id = 0;
+ int capnum;
+
+ if (pass == 2) {
+ id = queue_remove(id_queue);
+ free(id);
+ return 0;
+ }
+
+ id = (char *)queue_remove(id_queue);
+ if (!id) {
+ yyerror("no capability name for policycap definition?");
+ goto bad;
+ }
+#ifdef HAVE_SEPOL_POLICYCAPS
+ /* Check for valid cap name -> number mapping */
+ capnum = sepol_polcap_getnum(id);
+ if (capnum < 0) {
+ yyerror2("invalid policy capability name %s", id);
+ goto bad;
+ }
+
+ /* Store it */
+ if (ebitmap_set_bit(&policydbp->policycaps, capnum, TRUE)) {
+ yyerror("out of memory");
+ goto bad;
+ }
+#else
+ yyerror("This version of SETools does not have policycap enabled.");
+#endif
+
+ free(id);
+ return 0;
+
+ bad:
+ free(id);
+ return -1;
+}
+
+int define_initial_sid(void)
+{
+ char *id = 0;
+ ocontext_t *newc = 0, *c, *head;
+
+ if (pass == 2) {
+ id = queue_remove(id_queue);
+ free(id);
+ return 0;
+ }
+
+ id = (char *)queue_remove(id_queue);
+ if (!id) {
+ yyerror("no sid name for SID definition?");
+ return -1;
+ }
+ newc = (ocontext_t *) malloc(sizeof(ocontext_t));
+ if (!newc) {
+ yyerror("out of memory");
+ goto bad;
+ }
+ memset(newc, 0, sizeof(ocontext_t));
+ newc->u.name = id;
+ context_init(&newc->context[0]);
+ head = policydbp->ocontexts[OCON_ISID];
+
+ for (c = head; c; c = c->next) {
+ if (!strcmp(newc->u.name, c->u.name)) {
+ yyerror2("duplicate initial SID %s", id);
+ goto bad;
+ }
+ }
+
+ if (head) {
+ newc->sid[0] = head->sid[0] + 1;
+ } else {
+ newc->sid[0] = 1;
+ }
+ newc->next = head;
+ policydbp->ocontexts[OCON_ISID] = newc;
+
+ return 0;
+
+ bad:
+ if (id)
+ free(id);
+ if (newc)
+ free(newc);
+ return -1;
+}
+
+int define_common_perms(void)
+{
+ char *id = 0, *perm = 0;
+ common_datum_t *comdatum = 0;
+ perm_datum_t *perdatum = 0;
+ int ret;
+
+ if (pass == 2) {
+ while ((id = queue_remove(id_queue)))
+ free(id);
+ return 0;
+ }
+
+ id = (char *)queue_remove(id_queue);
+ if (!id) {
+ yyerror("no common name for common perm definition?");
+ return -1;
+ }
+ comdatum = hashtab_search(policydbp->p_commons.table, id);
+ if (comdatum) {
+ yyerror2("duplicate declaration for common %s\n", id);
+ return -1;
+ }
+ comdatum = (common_datum_t *) malloc(sizeof(common_datum_t));
+ if (!comdatum) {
+ yyerror("out of memory");
+ goto bad;
+ }
+ memset(comdatum, 0, sizeof(common_datum_t));
+ ret = hashtab_insert(policydbp->p_commons.table, (hashtab_key_t) id, (hashtab_datum_t) comdatum);
+
+ if (ret == SEPOL_EEXIST) {
+ yyerror("duplicate common definition");
+ goto bad;
+ }
+ if (ret == SEPOL_ENOMEM) {
+ yyerror("hash table overflow");
+ goto bad;
+ }
+ comdatum->s.value = policydbp->p_commons.nprim + 1;
+ if (symtab_init(&comdatum->permissions, PERM_SYMTAB_SIZE)) {
+ yyerror("out of memory");
+ goto bad;
+ }
+ policydbp->p_commons.nprim++;
+ while ((perm = queue_remove(id_queue))) {
+ perdatum = (perm_datum_t *) malloc(sizeof(perm_datum_t));
+ if (!perdatum) {
+ yyerror("out of memory");
+ goto bad_perm;
+ }
+ memset(perdatum, 0, sizeof(perm_datum_t));
+ perdatum->s.value = comdatum->permissions.nprim + 1;
+
+ if (perdatum->s.value > (sizeof(sepol_access_vector_t) * 8)) {
+ yyerror("too many permissions to fit in an access vector");
+ goto bad_perm;
+ }
+ ret = hashtab_insert(comdatum->permissions.table, (hashtab_key_t) perm, (hashtab_datum_t) perdatum);
+
+ if (ret == SEPOL_EEXIST) {
+ yyerror2("duplicate permission %s in common %s", perm, id);
+ goto bad_perm;
+ }
+ if (ret == SEPOL_ENOMEM) {
+ yyerror("hash table overflow");
+ goto bad_perm;
+ }
+ comdatum->permissions.nprim++;
+ }
+
+ return 0;
+
+ bad:
+ if (id)
+ free(id);
+ if (comdatum)
+ free(comdatum);
+ return -1;
+
+ bad_perm:
+ if (perm)
+ free(perm);
+ if (perdatum)
+ free(perdatum);
+ return -1;
+}
+
+int define_av_perms(int inherits)
+{
+ char *id;
+ class_datum_t *cladatum;
+ common_datum_t *comdatum;
+ perm_datum_t *perdatum = 0, *perdatum2 = 0;
+ int ret;
+
+ if (pass == 2) {
+ while ((id = queue_remove(id_queue)))
+ free(id);
+ return 0;
+ }
+
+ id = (char *)queue_remove(id_queue);
+ if (!id) {
+ yyerror("no tclass name for av perm definition?");
+ return -1;
+ }
+ cladatum = (class_datum_t *) hashtab_search(policydbp->p_classes.table, (hashtab_key_t) id);
+ if (!cladatum) {
+ yyerror2("class %s is not defined", id);
+ goto bad;
+ }
+ free(id);
+
+ if (cladatum->comdatum || cladatum->permissions.nprim) {
+ yyerror("duplicate access vector definition");
+ return -1;
+ }
+ if (symtab_init(&cladatum->permissions, PERM_SYMTAB_SIZE)) {
+ yyerror("out of memory");
+ return -1;
+ }
+ if (inherits) {
+ id = (char *)queue_remove(id_queue);
+ if (!id) {
+ yyerror("no inherits name for access vector definition?");
+ return -1;
+ }
+ comdatum = (common_datum_t *) hashtab_search(policydbp->p_commons.table, (hashtab_key_t) id);
+
+ if (!comdatum) {
+ yyerror2("common %s is not defined", id);
+ goto bad;
+ }
+ cladatum->comkey = id;
+ cladatum->comdatum = comdatum;
+
+ /*
+ * Class-specific permissions start with values
+ * after the last common permission.
+ */
+ cladatum->permissions.nprim += comdatum->permissions.nprim;
+ }
+ while ((id = queue_remove(id_queue))) {
+ perdatum = (perm_datum_t *) malloc(sizeof(perm_datum_t));
+ if (!perdatum) {
+ yyerror("out of memory");
+ goto bad;
+ }
+ memset(perdatum, 0, sizeof(perm_datum_t));
+ perdatum->s.value = ++cladatum->permissions.nprim;
+
+ if (perdatum->s.value > (sizeof(sepol_access_vector_t) * 8)) {
+ yyerror("too many permissions to fit in an access vector");
+ goto bad;
+ }
+ if (inherits) {
+ /*
+ * Class-specific permissions and
+ * common permissions exist in the same
+ * name space.
+ */
+ perdatum2 = (perm_datum_t *) hashtab_search(cladatum->comdatum->permissions.table, (hashtab_key_t) id);
+ if (perdatum2) {
+ yyerror2("permission %s conflicts with an " "inherited permission", id);
+ goto bad;
+ }
+ }
+ ret = hashtab_insert(cladatum->permissions.table, (hashtab_key_t) id, (hashtab_datum_t) perdatum);
+
+ if (ret == SEPOL_EEXIST) {
+ yyerror2("duplicate permission %s", id);
+ goto bad;
+ }
+ if (ret == SEPOL_ENOMEM) {
+ yyerror("hash table overflow");
+ goto bad;
+ }
+ if (add_perm_to_class(perdatum->s.value, cladatum->s.value)) {
+ yyerror("out of memory");
+ goto bad;
+ }
+ }
+
+ return 0;
+
+ bad:
+ if (id)
+ free(id);
+ if (perdatum)
+ free(perdatum);
+ return -1;
+}
+
+int define_sens(void)
+{
+ char *id;
+ mls_level_t *level = 0;
+ level_datum_t *datum = 0, *aliasdatum = 0;
+ int ret;
+ uint32_t value; /* dummy variable -- its value is never used */
+
+ if (!mlspol) {
+ yyerror("sensitivity definition in non-MLS configuration");
+ return -1;
+ }
+
+ if (pass == 2) {
+ while ((id = queue_remove(id_queue)))
+ free(id);
+ return 0;
+ }
+
+ id = (char *)queue_remove(id_queue);
+ if (!id) {
+ yyerror("no sensitivity name for sensitivity definition?");
+ return -1;
+ }
+ if (id_has_dot(id)) {
+ yyerror("sensitivity identifiers may not contain periods");
+ goto bad;
+ }
+ level = (mls_level_t *) malloc(sizeof(mls_level_t));
+ if (!level) {
+ yyerror("out of memory");
+ goto bad;
+ }
+ mls_level_init(level);
+ level->sens = 0; /* actual value set in define_dominance */
+ ebitmap_init(&level->cat); /* actual value set in define_level */
+
+ datum = (level_datum_t *) malloc(sizeof(level_datum_t));
+ if (!datum) {
+ yyerror("out of memory");
+ goto bad;
+ }
+ level_datum_init(datum);
+ datum->isalias = FALSE;
+ datum->level = level;
+
+ ret = declare_symbol(SYM_LEVELS, id, datum, &value, &value);
+ switch (ret) {
+ case -3:{
+ yyerror("Out of memory!");
+ goto bad;
+ }
+ case -2:{
+ yyerror("duplicate declaration of sensitivity level");
+ goto bad;
+ }
+ case -1:{
+ yyerror("could not declare sensitivity level here");
+ goto bad;
+ }
+ case 0:
+ case 1:{
+ break;
+ }
+ default:{
+ assert(0); /* should never get here */
+ }
+ }
+
+ while ((id = queue_remove(id_queue))) {
+ if (id_has_dot(id)) {
+ yyerror("sensitivity aliases may not contain periods");
+ goto bad_alias;
+ }
+ aliasdatum = (level_datum_t *) malloc(sizeof(level_datum_t));
+ if (!aliasdatum) {
+ yyerror("out of memory");
+ goto bad_alias;
+ }
+ level_datum_init(aliasdatum);
+ aliasdatum->isalias = TRUE;
+ aliasdatum->level = level;
+
+ ret = declare_symbol(SYM_LEVELS, id, aliasdatum, NULL, &value);
+ switch (ret) {
+ case -3:{
+ yyerror("Out of memory!");
+ goto bad_alias;
+ }
+ case -2:{
+ yyerror("duplicate declaration of sensitivity alias");
+ goto bad_alias;
+ }
+ case -1:{
+ yyerror("could not declare sensitivity alias here");
+ goto bad_alias;
+ }
+ case 0:
+ case 1:{
+ break;
+ }
+ default:{
+ assert(0); /* should never get here */
+ }
+ }
+ }
+
+ return 0;
+
+ bad:
+ if (id)
+ free(id);
+ if (level)
+ free(level);
+ if (datum) {
+ level_datum_destroy(datum);
+ free(datum);
+ }
+ return -1;
+
+ bad_alias:
+ if (id)
+ free(id);
+ if (aliasdatum) {
+ level_datum_destroy(aliasdatum);
+ free(aliasdatum);
+ }
+ return -1;
+}
+
+int define_dominance(void)
+{
+ level_datum_t *datum;
+ int order;
+ char *id;
+
+ if (!mlspol) {
+ yyerror("dominance definition in non-MLS configuration");
+ return -1;
+ }
+
+ if (pass == 2) {
+ while ((id = queue_remove(id_queue)))
+ free(id);
+ return 0;
+ }
+
+ order = 0;
+ while ((id = (char *)queue_remove(id_queue))) {
+ datum = (level_datum_t *) hashtab_search(policydbp->p_levels.table, (hashtab_key_t) id);
+ if (!datum) {
+ yyerror2("unknown sensitivity %s used in dominance " "definition", id);
+ free(id);
+ return -1;
+ }
+ if (datum->level->sens != 0) {
+ yyerror2("sensitivity %s occurs multiply in dominance " "definition", id);
+ free(id);
+ return -1;
+ }
+ datum->level->sens = ++order;
+
+ /* no need to keep sensitivity name */
+ free(id);
+ }
+
+ if (order != policydbp->p_levels.nprim) {
+ yyerror("all sensitivities must be specified in dominance definition");
+ return -1;
+ }
+ return 0;
+}
+
+int define_category(void)
+{
+ char *id;
+ cat_datum_t *datum = 0, *aliasdatum = 0;
+ int ret;
+ uint32_t value;
+
+ if (!mlspol) {
+ yyerror("category definition in non-MLS configuration");
+ return -1;
+ }
+
+ if (pass == 2) {
+ while ((id = queue_remove(id_queue)))
+ free(id);
+ return 0;
+ }
+
+ id = (char *)queue_remove(id_queue);
+ if (!id) {
+ yyerror("no category name for category definition?");
+ return -1;
+ }
+ if (id_has_dot(id)) {
+ yyerror("category identifiers may not contain periods");
+ goto bad;
+ }
+ datum = (cat_datum_t *) malloc(sizeof(cat_datum_t));
+ if (!datum) {
+ yyerror("out of memory");
+ goto bad;
+ }
+ cat_datum_init(datum);
+ datum->isalias = FALSE;
+
+ ret = declare_symbol(SYM_CATS, id, datum, &value, &value);
+ switch (ret) {
+ case -3:{
+ yyerror("Out of memory!");
+ goto bad;
+ }
+ case -2:{
+ yyerror("duplicate declaration of category");
+ goto bad;
+ }
+ case -1:{
+ yyerror("could not declare category here");
+ goto bad;
+ }
+ case 0:
+ case 1:{
+ break;
+ }
+ default:{
+ assert(0); /* should never get here */
+ }
+ }
+ datum->s.value = value;
+
+ while ((id = queue_remove(id_queue))) {
+ if (id_has_dot(id)) {
+ yyerror("category aliases may not contain periods");
+ goto bad_alias;
+ }
+ aliasdatum = (cat_datum_t *) malloc(sizeof(cat_datum_t));
+ if (!aliasdatum) {
+ yyerror("out of memory");
+ goto bad_alias;
+ }
+ cat_datum_init(aliasdatum);
+ aliasdatum->isalias = TRUE;
+ aliasdatum->s.value = datum->s.value;
+
+ ret = declare_symbol(SYM_CATS, id, aliasdatum, NULL, &datum->s.value);
+ switch (ret) {
+ case -3:{
+ yyerror("Out of memory!");
+ goto bad_alias;
+ }
+ case -2:{
+ yyerror("duplicate declaration of category aliases");
+ goto bad_alias;
+ }
+ case -1:{
+ yyerror("could not declare category aliases here");
+ goto bad_alias;
+ }
+ case 0:
+ case 1:{
+ break;
+ }
+ default:{
+ assert(0); /* should never get here */
+ }
+ }
+ }
+
+ return 0;
+
+ bad:
+ if (id)
+ free(id);
+ if (datum) {
+ cat_datum_destroy(datum);
+ free(datum);
+ }
+ return -1;
+
+ bad_alias:
+ if (id)
+ free(id);
+ if (aliasdatum) {
+ cat_datum_destroy(aliasdatum);
+ free(aliasdatum);
+ }
+ return -1;
+}
+
+static int clone_level(hashtab_key_t key, hashtab_datum_t datum, void *arg)
+{
+ level_datum_t *levdatum = (level_datum_t *) datum;
+ mls_level_t *level = (mls_level_t *) arg, *newlevel;
+
+ if (levdatum->level == level) {
+ levdatum->defined = 1;
+ if (!levdatum->isalias)
+ return 0;
+ newlevel = (mls_level_t *) malloc(sizeof(mls_level_t));
+ if (!newlevel)
+ return -1;
+ if (mls_level_cpy(newlevel, level)) {
+ free(newlevel);
+ return -1;
+ }
+ levdatum->level = newlevel;
+ }
+ return 0;
+}
+
+int define_level(void)
+{
+ char *id;
+ level_datum_t *levdatum;
+
+ if (!mlspol) {
+ yyerror("level definition in non-MLS configuration");
+ return -1;
+ }
+
+ if (pass == 2) {
+ while ((id = queue_remove(id_queue)))
+ free(id);
+ return 0;
+ }
+
+ id = (char *)queue_remove(id_queue);
+ if (!id) {
+ yyerror("no level name for level definition?");
+ return -1;
+ }
+ levdatum = (level_datum_t *) hashtab_search(policydbp->p_levels.table, (hashtab_key_t) id);
+ if (!levdatum) {
+ yyerror2("unknown sensitivity %s used in level definition", id);
+ free(id);
+ return -1;
+ }
+ if (ebitmap_length(&levdatum->level->cat)) {
+ yyerror2("sensitivity %s used in multiple level definitions", id);
+ free(id);
+ return -1;
+ }
+ free(id);
+
+ levdatum->defined = 1;
+
+ while ((id = queue_remove(id_queue))) {
+ cat_datum_t *cdatum;
+ int range_start, range_end, i;
+
+ if (id_has_dot(id)) {
+ char *id_start = id;
+ char *id_end = strchr(id, '.');
+
+ *(id_end++) = '\0';
+
+ cdatum = (cat_datum_t *) hashtab_search(policydbp->p_cats.table, (hashtab_key_t)
+ id_start);
+ if (!cdatum) {
+ yyerror2("unknown category %s", id_start);
+ free(id);
+ return -1;
+ }
+ range_start = cdatum->s.value - 1;
+ cdatum = (cat_datum_t *) hashtab_search(policydbp->p_cats.table, (hashtab_key_t)
+ id_end);
+ if (!cdatum) {
+ yyerror2("unknown category %s", id_end);
+ free(id);
+ return -1;
+ }
+ range_end = cdatum->s.value - 1;
+
+ if (range_end < range_start) {
+ yyerror2("category range is invalid");
+ free(id);
+ return -1;
+ }
+ } else {
+ cdatum = (cat_datum_t *) hashtab_search(policydbp->p_cats.table, (hashtab_key_t) id);
+ range_start = range_end = cdatum->s.value - 1;
+ }
+
+ for (i = range_start; i <= range_end; i++) {
+ if (ebitmap_set_bit(&levdatum->level->cat, i, TRUE)) {
+ yyerror("out of memory");
+ free(id);
+ return -1;
+ }
+ }
+
+ free(id);
+ }
+
+ if (hashtab_map(policydbp->p_levels.table, clone_level, levdatum->level)) {
+ yyerror("out of memory");
+ return -1;
+ }
+
+ return 0;
+}
+
+int define_attrib(void)
+{
+ if (pass == 2) {
+ free(queue_remove(id_queue));
+ return 0;
+ }
+
+ if (declare_type(TRUE, TRUE) == NULL) {
+ return -1;
+ }
+ return 0;
+}
+
+static int add_aliases_to_type(type_datum_t * type)
+{
+ char *id;
+ type_datum_t *aliasdatum = NULL;
+ int ret;
+ while ((id = queue_remove(id_queue))) {
+ if (id_has_dot(id)) {
+ free(id);
+ yyerror("type alias identifiers may not contain periods");
+ return -1;
+ }
+ aliasdatum = (type_datum_t *) malloc(sizeof(type_datum_t));
+ if (!aliasdatum) {
+ free(id);
+ yyerror("Out of memory!");
+ return -1;
+ }
+ memset(aliasdatum, 0, sizeof(type_datum_t));
+ aliasdatum->s.value = type->s.value;
+
+ ret = declare_symbol(SYM_TYPES, id, aliasdatum, NULL, &aliasdatum->s.value);
+ switch (ret) {
+ case -3:{
+ yyerror("Out of memory!");
+ goto cleanup;
+ }
+ case -2:{
+ yyerror2("duplicate declaration of alias %s", id);
+ goto cleanup;
+ }
+ case -1:{
+ yyerror("could not declare alias here");
+ goto cleanup;
+ }
+ case 0:
+ break;
+ case 1:{
+ /* ret == 1 means the alias was required and therefore already
+ * has a value. Set it up as an alias with a different primary. */
+ type_datum_destroy(aliasdatum);
+ free(aliasdatum);
+
+ aliasdatum = hashtab_search(policydbp->symtab[SYM_TYPES].table, id);
+ assert(aliasdatum);
+
+ aliasdatum->primary = type->s.value;
+ aliasdatum->flavor = TYPE_ALIAS;
+
+ break;
+ }
+ default:{
+ assert(0); /* should never get here */
+ }
+ }
+ }
+ return 0;
+ cleanup:
+ free(id);
+ type_datum_destroy(aliasdatum);
+ free(aliasdatum);
+ return -1;
+}
+
+int define_typealias(void)
+{
+ char *id;
+ type_datum_t *t;
+
+ if (pass == 2) {
+ while ((id = queue_remove(id_queue)))
+ free(id);
+ return 0;
+ }
+
+ id = (char *)queue_remove(id_queue);
+ if (!id) {
+ yyerror("no type name for typealias definition?");
+ return -1;
+ }
+
+ if (!is_id_in_scope(SYM_TYPES, id)) {
+ yyerror2("type %s is not within scope", id);
+ free(id);
+ return -1;
+ }
+ t = hashtab_search(policydbp->p_types.table, id);
+ if (!t || t->flavor == TYPE_ATTRIB) {
+ yyerror2("unknown type %s, or it was already declared as an " "attribute", id);
+ free(id);
+ return -1;
+ }
+ free(id);
+ return add_aliases_to_type(t);
+}
+
+int define_typeattribute(void)
+{
+ char *id;
+ type_datum_t *t, *attr;
+
+ if (pass == 2) {
+ while ((id = queue_remove(id_queue)))
+ free(id);
+ return 0;
+ }
+
+ id = (char *)queue_remove(id_queue);
+ if (!id) {
+ yyerror("no type name for typeattribute definition?");
+ return -1;
+ }
+
+ if (!is_id_in_scope(SYM_TYPES, id)) {
+ yyerror2("type %s is not within scope", id);
+ free(id);
+ return -1;
+ }
+ t = hashtab_search(policydbp->p_types.table, id);
+ if (!t || t->flavor == TYPE_ATTRIB) {
+ yyerror2("unknown type %s", id);
+ free(id);
+ return -1;
+ }
+ free(id);
+
+ while ((id = queue_remove(id_queue))) {
+ if (!is_id_in_scope(SYM_TYPES, id)) {
+ yyerror2("attribute %s is not within scope", id);
+ free(id);
+ return -1;
+ }
+ attr = hashtab_search(policydbp->p_types.table, id);
+ if (!attr) {
+ /* treat it as a fatal error */
+ yyerror2("attribute %s is not declared", id);
+ free(id);
+ return -1;
+ }
+
+ if (attr->flavor != TYPE_ATTRIB) {
+ yyerror2("%s is a type, not an attribute", id);
+ free(id);
+ return -1;
+ }
+
+ if ((attr = get_local_type(id, attr->s.value, 1)) == NULL) {
+ yyerror("Out of memory!");
+ return -1;
+ }
+
+ if (ebitmap_set_bit(&attr->types, (t->s.value - 1), TRUE)) {
+ yyerror("out of memory");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int define_typebounds_helper(char *bounds_id, char *type_id)
+{
+ type_datum_t *bounds, *type;
+
+ if (!is_id_in_scope(SYM_TYPES, bounds_id)) {
+ yyerror2("type %s is not within scope", bounds_id);
+ return -1;
+ }
+
+ bounds = hashtab_search(policydbp->p_types.table, bounds_id);
+ if (!bounds || bounds->flavor == TYPE_ATTRIB) {
+ yyerror2("hoge unknown type %s", bounds_id);
+ return -1;
+ }
+
+ if (!is_id_in_scope(SYM_TYPES, type_id)) {
+ yyerror2("type %s is not within scope", type_id);
+ return -1;
+ }
+
+ type = hashtab_search(policydbp->p_types.table, type_id);
+ if (!type || type->flavor == TYPE_ATTRIB) {
+ yyerror2("type %s is not declared", type_id);
+ return -1;
+ }
+
+ if (type->flavor == TYPE_TYPE && !type->primary) {
+ type = policydbp->type_val_to_struct[type->s.value - 1];
+ } else if (type->flavor == TYPE_ALIAS) {
+ type = policydbp->type_val_to_struct[type->primary - 1];
+ }
+
+ if (!type->bounds)
+ type->bounds = bounds->s.value;
+ else if (type->bounds != bounds->s.value) {
+ yyerror2("type %s has inconsistent master {%s,%s}",
+ type_id,
+ policydbp->p_type_val_to_name[type->bounds - 1], policydbp->p_type_val_to_name[bounds->s.value - 1]);
+ return -1;
+ }
+
+ return 0;
+}
+
+int define_typebounds(void)
+{
+ char *bounds, *id;
+
+ if (pass == 1) {
+ while ((id = queue_remove(id_queue)))
+ free(id);
+ return 0;
+ }
+
+ bounds = (char *)queue_remove(id_queue);
+ if (!bounds) {
+ yyerror("no type name for typebounds definition?");
+ return -1;
+ }
+
+ while ((id = queue_remove(id_queue))) {
+ if (define_typebounds_helper(bounds, id))
+ return -1;
+ free(id);
+ }
+ free(bounds);
+
+ return 0;
+}
+
+int define_type(int alias)
+{
+ char *id;
+ type_datum_t *datum, *attr;
+ int newattr = 0;
+
+ if (pass == 2) {
+ /*
+ * If type name contains ".", we have to define boundary
+ * relationship implicitly to keep compatibility with
+ * old name based hierarchy.
+ */
+ if ((id = queue_remove(id_queue))) {
+ char *bounds, *delim;
+
+ if ((delim = strrchr(id, '.'))
+ && (bounds = strdup(id))) {
+ bounds[(size_t) (delim - id)] = '\0';
+
+ if (define_typebounds_helper(bounds, id))
+ return -1;
+ free(bounds);
+ }
+ free(id);
+ }
+
+ if (alias) {
+ while ((id = queue_remove(id_queue)))
+ free(id);
+ }
+
+ while ((id = queue_remove(id_queue)))
+ free(id);
+ return 0;
+ }
+
+ if ((datum = declare_type(TRUE, FALSE)) == NULL) {
+ return -1;
+ }
+
+ if (alias) {
+ if (add_aliases_to_type(datum) == -1) {
+ return -1;
+ }
+ }
+
+ while ((id = queue_remove(id_queue))) {
+ if (!is_id_in_scope(SYM_TYPES, id)) {
+ yyerror2("attribute %s is not within scope", id);
+ free(id);
+ return -1;
+ }
+ attr = hashtab_search(policydbp->p_types.table, id);
+ if (!attr) {
+ /* treat it as a fatal error */
+ yyerror2("attribute %s is not declared", id);
+ return -1;
+ } else {
+ newattr = 0;
+ }
+
+ if (attr->flavor != TYPE_ATTRIB) {
+ yyerror2("%s is a type, not an attribute", id);
+ return -1;
+ }
+
+ if ((attr = get_local_type(id, attr->s.value, 1)) == NULL) {
+ yyerror("Out of memory!");
+ return -1;
+ }
+
+ if (ebitmap_set_bit(&attr->types, datum->s.value - 1, TRUE)) {
+ yyerror("Out of memory");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+struct val_to_name
+{
+ unsigned int val;
+ char *name;
+};
+
+/* Adds a type, given by its textual name, to a typeset. If *add is
+ 0, then add the type to the negative set; otherwise if *add is 1
+ then add it to the positive side. */
+static int set_types(type_set_t * set, char *id, int *add, char starallowed)
+{
+ type_datum_t *t;
+
+ if (strcmp(id, "*") == 0) {
+ if (!starallowed) {
+ yyerror("* not allowed in this type of rule");
+ return -1;
+ }
+ /* set TYPE_STAR flag */
+ set->flags = TYPE_STAR;
+ free(id);
+ *add = 1;
+ return 0;
+ }
+
+ if (strcmp(id, "~") == 0) {
+ if (!starallowed) {
+ yyerror("~ not allowed in this type of rule");
+ return -1;
+ }
+ /* complement the set */
+ set->flags = TYPE_COMP;
+ free(id);
+ *add = 1;
+ return 0;
+ }
+
+ if (strcmp(id, "-") == 0) {
+ *add = 0;
+ free(id);
+ return 0;
+ }
+
+ if (!is_id_in_scope(SYM_TYPES, id)) {
+ yyerror2("type %s is not within scope", id);
+ free(id);
+ return -1;
+ }
+ t = hashtab_search(policydbp->p_types.table, id);
+ if (!t) {
+ yyerror2("unknown type %s", id);
+ free(id);
+ return -1;
+ }
+
+ if (*add == 0) {
+ if (ebitmap_set_bit(&set->negset, t->s.value - 1, TRUE))
+ goto oom;
+ } else {
+ if (ebitmap_set_bit(&set->types, t->s.value - 1, TRUE))
+ goto oom;
+ }
+ free(id);
+ *add = 1;
+ return 0;
+ oom:
+ yyerror("Out of memory");
+ free(id);
+ return -1;
+}
+
+int define_compute_type_helper(int which, avrule_t ** rule)
+{
+ char *id;
+ type_datum_t *datum;
+ class_datum_t *cladatum;
+ ebitmap_t tclasses;
+ ebitmap_node_t *node;
+ avrule_t *avrule;
+ class_perm_node_t *perm;
+ int i, add = 1;
+
+ avrule = malloc(sizeof(avrule_t));
+ if (!avrule) {
+ yyerror("out of memory");
+ return -1;
+ }
+ avrule_init(avrule);
+ avrule->specified = which;
+ avrule->line = policydb_lineno;
+
+ while ((id = queue_remove(id_queue))) {
+ if (set_types(&avrule->stypes, id, &add, 0))
+ return -1;
+ }
+ add = 1;
+ while ((id = queue_remove(id_queue))) {
+ if (set_types(&avrule->ttypes, id, &add, 0))
+ return -1;
+ }
+
+ ebitmap_init(&tclasses);
+ while ((id = queue_remove(id_queue))) {
+ if (!is_id_in_scope(SYM_CLASSES, id)) {
+ yyerror2("class %s is not within scope", id);
+ free(id);
+ goto bad;
+ }
+ cladatum = hashtab_search(policydbp->p_classes.table, id);
+ if (!cladatum) {
+ yyerror2("unknown class %s", id);
+ goto bad;
+ }
+ if (ebitmap_set_bit(&tclasses, cladatum->s.value - 1, TRUE)) {
+ yyerror("Out of memory");
+ goto bad;
+ }
+ free(id);
+ }
+
+ id = (char *)queue_remove(id_queue);
+ if (!id) {
+ yyerror("no newtype?");
+ goto bad;
+ }
+ if (!is_id_in_scope(SYM_TYPES, id)) {
+ yyerror2("type %s is not within scope", id);
+ free(id);
+ goto bad;
+ }
+ datum = (type_datum_t *) hashtab_search(policydbp->p_types.table, (hashtab_key_t) id);
+ if (!datum || datum->flavor == TYPE_ATTRIB) {
+ yyerror2("unknown type %s", id);
+ goto bad;
+ }
+ free(id);
+
+ ebitmap_for_each_bit(&tclasses, node, i) {
+ if (ebitmap_node_get_bit(node, i)) {
+ perm = malloc(sizeof(class_perm_node_t));
+ if (!perm) {
+ yyerror("out of memory");
+ return -1;
+ }
+ class_perm_node_init(perm);
+ perm->class = i + 1;
+ perm->data = datum->s.value;
+ perm->next = avrule->perms;
+ avrule->perms = perm;
+ }
+ }
+ ebitmap_destroy(&tclasses);
+
+ *rule = avrule;
+ return 0;
+
+ bad:
+ avrule_destroy(avrule);
+ free(avrule);
+ return -1;
+}
+
+int define_compute_type(int which)
+{
+ char *id;
+ avrule_t *avrule;
+ int retval;
+
+ if (pass == 1 || (num_rules && !load_rules)) {
+ while ((id = queue_remove(id_queue)))
+ free(id);
+ while ((id = queue_remove(id_queue)))
+ free(id);
+ while ((id = queue_remove(id_queue)))
+ free(id);
+ id = queue_remove(id_queue);
+ free(id);
+ return 0;
+ }
+
+ num_rules++;
+
+ if (define_compute_type_helper(which, &avrule))
+ return -1;
+
+ retval = insert_check_type_rule(avrule, &policydbp->te_avtab, NULL, NULL);
+ switch (retval) {
+ case 1:{
+ /* append this avrule to the end of the current rules list */
+ append_avrule(avrule);
+ return 0;
+ }
+ case 2: /* FALLTHROUGH */
+ case 0:{
+ /* rule conflicted, so don't actually add this rule */
+ avrule_destroy(avrule);
+ free(avrule);
+ return 0;
+ }
+ case -1:{
+ avrule_destroy(avrule);
+ free(avrule);
+ return -1;
+ }
+ default:{
+ assert(0); /* should never get here */
+ }
+ }
+}
+
+avrule_t *define_cond_compute_type(int which)
+{
+ char *id;
+ avrule_t *avrule;
+
+ if (pass == 1 || (num_rules && !load_rules)) {
+ while ((id = queue_remove(id_queue)))
+ free(id);
+ while ((id = queue_remove(id_queue)))
+ free(id);
+ while ((id = queue_remove(id_queue)))
+ free(id);
+ id = queue_remove(id_queue);
+ free(id);
+ return (avrule_t *) 1;
+ }
+
+ num_rules++;
+
+ if (define_compute_type_helper(which, &avrule))
+ return COND_ERR;
+
+ return avrule;
+}
+
+int define_bool(void)
+{
+ char *id, *bool_value;
+ cond_bool_datum_t *datum;
+ int ret;
+ uint32_t value;
+
+ if (pass == 2) {
+ while ((id = queue_remove(id_queue)))
+ free(id);
+ return 0;
+ }
+
+ id = (char *)queue_remove(id_queue);
+ if (!id) {
+ yyerror("no identifier for bool definition?");
+ return -1;
+ }
+ if (id_has_dot(id)) {
+ free(id);
+ yyerror("boolean identifiers may not contain periods");
+ return -1;
+ }
+ datum = (cond_bool_datum_t *) malloc(sizeof(cond_bool_datum_t));
+ if (!datum) {
+ yyerror("out of memory");
+ free(id);
+ return -1;
+ }
+ memset(datum, 0, sizeof(cond_bool_datum_t));
+ ret = declare_symbol(SYM_BOOLS, id, datum, &value, &value);
+ switch (ret) {
+ case -3:{
+ yyerror("Out of memory!");
+ goto cleanup;
+ }
+ case -2:{
+ yyerror2("duplicate declaration of boolean %s", id);
+ goto cleanup;
+ }
+ case -1:{
+ yyerror("could not declare boolean here");
+ goto cleanup;
+ }
+ case 0:
+ case 1:{
+ break;
+ }
+ default:{
+ assert(0); /* should never get here */
+ }
+ }
+ datum->s.value = value;
+
+ bool_value = (char *)queue_remove(id_queue);
+ if (!bool_value) {
+ yyerror("no default value for bool definition?");
+ free(id);
+ return -1;
+ }
+
+ datum->state = (int)(bool_value[0] == 'T') ? 1 : 0;
+ free(bool_value);
+ return 0;
+ cleanup:
+ cond_destroy_bool(id, datum, NULL);
+ return -1;
+}
+
+avrule_t *define_cond_pol_list(avrule_t * avlist, avrule_t * sl)
+{
+ if (pass == 1 || (num_rules && !load_rules)) {
+ /* return something so we get through pass 1 */
+ return (avrule_t *) 1;
+ }
+
+ if (sl == NULL) {
+ /* This is a require block, return previous list */
+ return avlist;
+ }
+
+ /* prepend the new avlist to the pre-existing one */
+ sl->next = avlist;
+ return sl;
+}
+
+int define_te_avtab_helper(int which, avrule_t ** rule)
+{
+ char *id;
+ class_datum_t *cladatum;
+ perm_datum_t *perdatum = NULL;
+ class_perm_node_t *perms, *tail = NULL, *cur_perms = NULL;
+ ebitmap_t tclasses;
+ ebitmap_node_t *node;
+ avrule_t *avrule;
+ unsigned int i;
+ int add = 1, ret = 0;
+ int suppress = 0;
+
+ avrule = (avrule_t *) malloc(sizeof(avrule_t));
+ if (!avrule) {
+ yyerror("memory error");
+ ret = -1;
+ goto out;
+ }
+ avrule_init(avrule);
+ avrule->specified = which;
+ avrule->line = policydb_lineno;
+
+ while ((id = queue_remove(id_queue))) {
+ if (set_types(&avrule->stypes, id, &add, which == AVRULE_NEVERALLOW ? 1 : 0)) {
+ ret = -1;
+ goto out;
+ }
+ }
+ add = 1;
+ while ((id = queue_remove(id_queue))) {
+ if (strcmp(id, "self") == 0) {
+ free(id);
+ avrule->flags |= RULE_SELF;
+ continue;
+ }
+ if (set_types(&avrule->ttypes, id, &add, which == AVRULE_NEVERALLOW ? 1 : 0)) {
+ ret = -1;
+ goto out;
+ }
+ }
+
+ ebitmap_init(&tclasses);
+ while ((id = queue_remove(id_queue))) {
+ if (!is_id_in_scope(SYM_CLASSES, id)) {
+ yyerror2("class %s is not within scope", id);
+ ret = -1;
+ goto out;
+ }
+ cladatum = hashtab_search(policydbp->p_classes.table, id);
+ if (!cladatum) {
+ yyerror2("unknown class %s used in rule", id);
+ ret = -1;
+ goto out;
+ }
+ if (ebitmap_set_bit(&tclasses, cladatum->s.value - 1, TRUE)) {
+ yyerror("Out of memory");
+ ret = -1;
+ goto out;
+ }
+ free(id);
+ }
+
+ perms = NULL;
+ ebitmap_for_each_bit(&tclasses, node, i) {
+ if (!ebitmap_node_get_bit(node, i))
+ continue;
+ cur_perms = (class_perm_node_t *) malloc(sizeof(class_perm_node_t));
+ if (!cur_perms) {
+ yyerror("out of memory");
+ ret = -1;
+ goto out;
+ }
+ class_perm_node_init(cur_perms);
+ cur_perms->class = i + 1;
+ if (!perms)
+ perms = cur_perms;
+ if (tail)
+ tail->next = cur_perms;
+ tail = cur_perms;
+ }
+
+ while ((id = queue_remove(id_queue))) {
+ cur_perms = perms;
+ ebitmap_for_each_bit(&tclasses, node, i) {
+ if (!ebitmap_node_get_bit(node, i))
+ continue;
+ cladatum = policydbp->class_val_to_struct[i];
+
+ if (strcmp(id, "*") == 0) {
+ /* set all permissions in the class */
+ cur_perms->data = ~0U;
+ goto next;
+ }
+
+ if (strcmp(id, "~") == 0) {
+ /* complement the set */
+ if (which == AVRULE_DONTAUDIT)
+ yywarn("dontaudit rule with a ~?");
+ cur_perms->data = ~cur_perms->data;
+ goto next;
+ }
+
+ perdatum = hashtab_search(cladatum->permissions.table, id);
+ if (!perdatum) {
+ if (cladatum->comdatum) {
+ perdatum = hashtab_search(cladatum->comdatum->permissions.table, id);
+ }
+ }
+ if (!perdatum) {
+ if (!suppress)
+ yyerror2("permission %s is not defined"
+ " for class %s", id, policydbp->p_class_val_to_name[i]);
+ continue;
+ } else if (!is_perm_in_scope(id, policydbp->p_class_val_to_name[i])) {
+ if (!suppress) {
+ yyerror2("permission %s of class %s is"
+ " not within scope", id, policydbp->p_class_val_to_name[i]);
+ }
+ continue;
+ } else {
+ cur_perms->data |= 1U << (perdatum->s.value - 1);
+ }
+ next:
+ cur_perms = cur_perms->next;
+ }
+
+ free(id);
+ }
+
+ ebitmap_destroy(&tclasses);
+
+ avrule->perms = perms;
+ *rule = avrule;
+
+ out:
+ return ret;
+
+}
+
+avrule_t *define_cond_te_avtab(int which)
+{
+ char *id;
+ avrule_t *avrule;
+ int i;
+
+ if (pass == 1 || (num_rules && !load_rules)) {
+ for (i = 0; i < 4; i++) {
+ while ((id = queue_remove(id_queue)))
+ free(id);
+ }
+ return (avrule_t *) 1; /* any non-NULL value */
+ }
+
+ num_rules++;
+
+ if (define_te_avtab_helper(which, &avrule))
+ return COND_ERR;
+
+ return avrule;
+}
+
+int define_te_avtab(int which)
+{
+ char *id;
+ avrule_t *avrule;
+ int i;
+
+ if (pass == 1 || (num_rules && !load_rules)) {
+ for (i = 0; i < 4; i++) {
+ while ((id = queue_remove(id_queue)))
+ free(id);
+ }
+ return 0;
+ }
+
+ num_rules++;
+
+ if (define_te_avtab_helper(which, &avrule))
+ return -1;
+
+ /* append this avrule to the end of the current rules list */
+ append_avrule(avrule);
+ return 0;
+}
+
+int define_role_types(void)
+{
+ role_datum_t *role;
+ char *id;
+ int add = 1;
+
+ if (pass == 1) {
+ while ((id = queue_remove(id_queue)))
+ free(id);
+ return 0;
+ }
+
+ if ((role = declare_role()) == NULL) {
+ return -1;
+ }
+ while ((id = queue_remove(id_queue))) {
+ if (set_types(&role->types, id, &add, 0))
+ return -1;
+ }
+
+ return 0;
+}
+
+role_datum_t *merge_roles_dom(role_datum_t * r1, role_datum_t * r2)
+{
+ role_datum_t *new;
+
+ if (pass == 1) {
+ return (role_datum_t *) 1; /* any non-NULL value */
+ }
+
+ new = malloc(sizeof(role_datum_t));
+ if (!new) {
+ yyerror("out of memory");
+ return NULL;
+ }
+ memset(new, 0, sizeof(role_datum_t));
+ new->s.value = 0; /* temporary role */
+ if (ebitmap_or(&new->dominates, &r1->dominates, &r2->dominates)) {
+ yyerror("out of memory");
+ return NULL;
+ }
+ if (ebitmap_or(&new->types.types, &r1->types.types, &r2->types.types)) {
+ yyerror("out of memory");
+ return NULL;
+ }
+ if (!r1->s.value) {
+ /* free intermediate result */
+ type_set_destroy(&r1->types);
+ ebitmap_destroy(&r1->dominates);
+ free(r1);
+ }
+ if (!r2->s.value) {
+ /* free intermediate result */
+ yyerror("right hand role is temporary?");
+ type_set_destroy(&r2->types);
+ ebitmap_destroy(&r2->dominates);
+ free(r2);
+ }
+ return new;
+}
+
+/* This function eliminates the ordering dependency of role dominance rule */
+static int dominate_role_recheck(hashtab_key_t key, hashtab_datum_t datum, void *arg)
+{
+ role_datum_t *rdp = (role_datum_t *) arg;
+ role_datum_t *rdatum = (role_datum_t *) datum;
+ ebitmap_node_t *node;
+ int i;
+
+ /* Don't bother to process against self role */
+ if (rdatum->s.value == rdp->s.value)
+ return 0;
+
+ /* If a dominating role found */
+ if (ebitmap_get_bit(&(rdatum->dominates), rdp->s.value - 1)) {
+ ebitmap_t types;
+ ebitmap_init(&types);
+ if (type_set_expand(&rdp->types, &types, policydbp, 1)) {
+ ebitmap_destroy(&types);
+ return -1;
+ }
+ /* raise types and dominates from dominated role */
+ ebitmap_for_each_bit(&rdp->dominates, node, i) {
+ if (ebitmap_node_get_bit(node, i))
+ if (ebitmap_set_bit(&rdatum->dominates, i, TRUE))
+ goto oom;
+ }
+ ebitmap_for_each_bit(&types, node, i) {
+ if (ebitmap_node_get_bit(node, i))
+ if (ebitmap_set_bit(&rdatum->types.types, i, TRUE))
+ goto oom;
+ }
+ ebitmap_destroy(&types);
+ }
+
+ /* go through all the roles */
+ return 0;
+ oom:
+ yyerror("Out of memory");
+ return -1;
+}
+
+role_datum_t *define_role_dom(role_datum_t * r)
+{
+ role_datum_t *role;
+ char *role_id;
+ ebitmap_node_t *node;
+ unsigned int i;
+ int ret;
+
+ if (pass == 1) {
+ role_id = queue_remove(id_queue);
+ free(role_id);
+ return (role_datum_t *) 1; /* any non-NULL value */
+ }
+
+ yywarn("Role dominance has been deprecated");
+
+ role_id = queue_remove(id_queue);
+ if (!is_id_in_scope(SYM_ROLES, role_id)) {
+ yyerror2("role %s is not within scope", role_id);
+ free(role_id);
+ return NULL;
+ }
+ role = (role_datum_t *) hashtab_search(policydbp->p_roles.table, role_id);
+ if (!role) {
+ role = (role_datum_t *) malloc(sizeof(role_datum_t));
+ if (!role) {
+ yyerror("out of memory");
+ free(role_id);
+ return NULL;
+ }
+ memset(role, 0, sizeof(role_datum_t));
+ ret = declare_symbol(SYM_ROLES, (hashtab_key_t) role_id, (hashtab_datum_t) role, &role->s.value, &role->s.value);
+ switch (ret) {
+ case -3:{
+ yyerror("Out of memory!");
+ goto cleanup;
+ }
+ case -2:{
+ yyerror2("duplicate declaration of role %s", role_id);
+ goto cleanup;
+ }
+ case -1:{
+ yyerror("could not declare role here");
+ goto cleanup;
+ }
+ case 0:
+ case 1:{
+ break;
+ }
+ default:{
+ assert(0); /* should never get here */
+ }
+ }
+ if (ebitmap_set_bit(&role->dominates, role->s.value - 1, TRUE)) {
+ yyerror("Out of memory!");
+ goto cleanup;
+ }
+ }
+ if (r) {
+ ebitmap_t types;
+ ebitmap_init(&types);
+ ebitmap_for_each_bit(&r->dominates, node, i) {
+ if (ebitmap_node_get_bit(node, i))
+ if (ebitmap_set_bit(&role->dominates, i, TRUE))
+ goto oom;
+ }
+ if (type_set_expand(&r->types, &types, policydbp, 1)) {
+ ebitmap_destroy(&types);
+ return NULL;
+ }
+ ebitmap_for_each_bit(&types, node, i) {
+ if (ebitmap_node_get_bit(node, i))
+ if (ebitmap_set_bit(&role->types.types, i, TRUE))
+ goto oom;
+ }
+ ebitmap_destroy(&types);
+ if (!r->s.value) {
+ /* free intermediate result */
+ type_set_destroy(&r->types);
+ ebitmap_destroy(&r->dominates);
+ free(r);
+ }
+ /*
+ * Now go through all the roles and escalate this role's
+ * dominates and types if a role dominates this role.
+ */
+ hashtab_map(policydbp->p_roles.table, dominate_role_recheck, role);
+ }
+ return role;
+ cleanup:
+ free(role_id);
+ role_datum_destroy(role);
+ free(role);
+ return NULL;
+ oom:
+ yyerror("Out of memory");
+ goto cleanup;
+}
+
+static int role_val_to_name_helper(hashtab_key_t key, hashtab_datum_t datum, void *p)
+{
+ struct val_to_name *v = p;
+ role_datum_t *roldatum;
+
+ roldatum = (role_datum_t *) datum;
+
+ if (v->val == roldatum->s.value) {
+ v->name = key;
+ return 1;
+ }
+
+ return 0;
+}
+
+static char *role_val_to_name(unsigned int val)
+{
+ struct val_to_name v;
+ int rc;
+
+ v.val = val;
+ rc = hashtab_map(policydbp->p_roles.table, role_val_to_name_helper, &v);
+ if (rc)
+ return v.name;
+ return NULL;
+}
+
+static int set_roles(role_set_t * set, char *id)
+{
+ role_datum_t *r;
+
+ if (strcmp(id, "*") == 0) {
+ free(id);
+ yyerror("* is not allowed for role sets");
+ return -1;
+ }
+
+ if (strcmp(id, "~") == 0) {
+ free(id);
+ yyerror("~ is not allowed for role sets");
+ return -1;
+ }
+ if (!is_id_in_scope(SYM_ROLES, id)) {
+ yyerror2("role %s is not within scope", id);
+ free(id);
+ return -1;
+ }
+ r = hashtab_search(policydbp->p_roles.table, id);
+ if (!r) {
+ yyerror2("unknown role %s", id);
+ free(id);
+ return -1;
+ }
+
+ if (ebitmap_set_bit(&set->roles, r->s.value - 1, TRUE)) {
+ yyerror("out of memory");
+ free(id);
+ return -1;
+ }
+ free(id);
+ return 0;
+}
+
+int define_role_trans(void)
+{
+ char *id;
+ role_datum_t *role;
+ role_set_t roles;
+ type_set_t types;
+ ebitmap_t e_types, e_roles;
+ ebitmap_node_t *tnode, *rnode;
+ struct role_trans *tr = NULL;
+ struct role_trans_rule *rule = NULL;
+ unsigned int i, j;
+ int add = 1;
+
+ if (pass == 1) {
+ while ((id = queue_remove(id_queue)))
+ free(id);
+ while ((id = queue_remove(id_queue)))
+ free(id);
+ id = queue_remove(id_queue);
+ free(id);
+ return 0;
+ }
+
+ role_set_init(&roles);
+ ebitmap_init(&e_roles);
+ type_set_init(&types);
+ ebitmap_init(&e_types);
+
+ while ((id = queue_remove(id_queue))) {
+ if (set_roles(&roles, id))
+ return -1;
+ }
+ add = 1;
+ while ((id = queue_remove(id_queue))) {
+ if (set_types(&types, id, &add, 0))
+ return -1;
+ }
+
+ id = (char *)queue_remove(id_queue);
+ if (!id) {
+ yyerror("no new role in transition definition?");
+ goto bad;
+ }
+ if (!is_id_in_scope(SYM_ROLES, id)) {
+ yyerror2("role %s is not within scope", id);
+ free(id);
+ goto bad;
+ }
+ role = hashtab_search(policydbp->p_roles.table, id);
+ if (!role) {
+ yyerror2("unknown role %s used in transition definition", id);
+ goto bad;
+ }
+ free(id);
+
+ /* This ebitmap business is just to ensure that there are not conflicting role_trans rules */
+#ifdef HAVE_SEPOL_USER_ROLE_MAPPING
+ if (role_set_expand(&roles, &e_roles, policydbp, NULL))
+#else
+ if (role_set_expand(&roles, &e_roles, policydbp))
+#endif
+ goto bad;
+
+ if (type_set_expand(&types, &e_types, policydbp, 1))
+ goto bad;
+
+ ebitmap_for_each_bit(&e_roles, rnode, i) {
+ if (!ebitmap_node_get_bit(rnode, i))
+ continue;
+ ebitmap_for_each_bit(&e_types, tnode, j) {
+ if (!ebitmap_node_get_bit(tnode, j))
+ continue;
+
+ for (tr = policydbp->role_tr; tr; tr = tr->next) {
+ if (tr->role == (i + 1) && tr->type == (j + 1)) {
+ yyerror2("duplicate role transition for (%s,%s)",
+ role_val_to_name(i + 1), policydbp->p_type_val_to_name[j]);
+ goto bad;
+ }
+ }
+
+ tr = malloc(sizeof(struct role_trans));
+ if (!tr) {
+ yyerror("out of memory");
+ return -1;
+ }
+ memset(tr, 0, sizeof(struct role_trans));
+ tr->role = i + 1;
+ tr->type = j + 1;
+ tr->new_role = role->s.value;
+ tr->next = policydbp->role_tr;
+ policydbp->role_tr = tr;
+ }
+ }
+ /* Now add the real rule */
+ rule = malloc(sizeof(struct role_trans_rule));
+ if (!rule) {
+ yyerror("out of memory");
+ return -1;
+ }
+ memset(rule, 0, sizeof(struct role_trans_rule));
+ rule->roles = roles;
+ rule->types = types;
+ rule->new_role = role->s.value;
+
+ append_role_trans(rule);
+
+ ebitmap_destroy(&e_roles);
+ ebitmap_destroy(&e_types);
+
+ return 0;
+
+ bad:
+ return -1;
+}
+
+int define_role_allow(void)
+{
+ char *id;
+ struct role_allow_rule *ra = 0;
+
+ if (pass == 1) {
+ while ((id = queue_remove(id_queue)))
+ free(id);
+ while ((id = queue_remove(id_queue)))
+ free(id);
+ return 0;
+ }
+
+ ra = malloc(sizeof(role_allow_rule_t));
+ if (!ra) {
+ yyerror("out of memory");
+ return -1;
+ }
+ role_allow_rule_init(ra);
+
+ while ((id = queue_remove(id_queue))) {
+ if (set_roles(&ra->roles, id))
+ return -1;
+ }
+
+ while ((id = queue_remove(id_queue))) {
+ if (set_roles(&ra->new_roles, id))
+ return -1;
+ }
+
+ append_role_allow(ra);
+ return 0;
+}
+
+static constraint_expr_t *constraint_expr_clone(constraint_expr_t * expr)
+{
+ constraint_expr_t *h = NULL, *l = NULL, *e, *newe;
+ for (e = expr; e; e = e->next) {
+ newe = malloc(sizeof(*newe));
+ if (!newe)
+ goto oom;
+ if (constraint_expr_init(newe) == -1) {
+ free(newe);
+ goto oom;
+ }
+ if (l)
+ l->next = newe;
+ else
+ h = newe;
+ l = newe;
+ newe->expr_type = e->expr_type;
+ newe->attr = e->attr;
+ newe->op = e->op;
+ if (newe->expr_type == CEXPR_NAMES) {
+ if (newe->attr & CEXPR_TYPE) {
+ if (type_set_cpy(newe->type_names, e->type_names))
+ goto oom;
+ } else {
+ if (ebitmap_cpy(&newe->names, &e->names))
+ goto oom;
+ }
+ }
+ }
+
+ return h;
+ oom:
+ e = h;
+ while (e) {
+ l = e;
+ e = e->next;
+ constraint_expr_destroy(l);
+ }
+ return NULL;
+}
+
+int define_constraint(constraint_expr_t * expr)
+{
+ struct constraint_node *node;
+ char *id;
+ class_datum_t *cladatum;
+ perm_datum_t *perdatum;
+ ebitmap_t classmap;
+ ebitmap_node_t *enode;
+ constraint_expr_t *e;
+ unsigned int i;
+ int depth;
+ unsigned char useexpr = 1;
+
+ if (pass == 1) {
+ while ((id = queue_remove(id_queue)))
+ free(id);
+ while ((id = queue_remove(id_queue)))
+ free(id);
+ return 0;
+ }
+
+ depth = -1;
+ for (e = expr; e; e = e->next) {
+ switch (e->expr_type) {
+ case CEXPR_NOT:
+ if (depth < 0) {
+ yyerror("illegal constraint expression");
+ return -1;
+ }
+ break;
+ case CEXPR_AND:
+ case CEXPR_OR:
+ if (depth < 1) {
+ yyerror("illegal constraint expression");
+ return -1;
+ }
+ depth--;
+ break;
+ case CEXPR_ATTR:
+ case CEXPR_NAMES:
+ if (e->attr & CEXPR_XTARGET) {
+ yyerror("illegal constraint expression");
+ return -1; /* only for validatetrans rules */
+ }
+ if (depth == (CEXPR_MAXDEPTH - 1)) {
+ yyerror("constraint expression is too deep");
+ return -1;
+ }
+ depth++;
+ break;
+ default:
+ yyerror("illegal constraint expression");
+ return -1;
+ }
+ }
+ if (depth != 0) {
+ yyerror("illegal constraint expression");
+ return -1;
+ }
+
+ ebitmap_init(&classmap);
+ while ((id = queue_remove(id_queue))) {
+ if (!is_id_in_scope(SYM_CLASSES, id)) {
+ yyerror2("class %s is not within scope", id);
+ free(id);
+ return -1;
+ }
+ cladatum = (class_datum_t *) hashtab_search(policydbp->p_classes.table, (hashtab_key_t) id);
+ if (!cladatum) {
+ yyerror2("class %s is not defined", id);
+ ebitmap_destroy(&classmap);
+ free(id);
+ return -1;
+ }
+ if (ebitmap_set_bit(&classmap, cladatum->s.value - 1, TRUE)) {
+ yyerror("out of memory");
+ ebitmap_destroy(&classmap);
+ free(id);
+ return -1;
+ }
+ node = malloc(sizeof(struct constraint_node));
+ if (!node) {
+ yyerror("out of memory");
+ return -1;
+ }
+ memset(node, 0, sizeof(constraint_node_t));
+ if (useexpr) {
+ node->expr = expr;
+ useexpr = 0;
+ } else {
+ node->expr = constraint_expr_clone(expr);
+ }
+ if (!node->expr) {
+ yyerror("out of memory");
+ return -1;
+ }
+ node->permissions = 0;
+
+ node->next = cladatum->constraints;
+ cladatum->constraints = node;
+
+ free(id);
+ }
+
+ while ((id = queue_remove(id_queue))) {
+ ebitmap_for_each_bit(&classmap, enode, i) {
+ if (ebitmap_node_get_bit(enode, i)) {
+ cladatum = policydbp->class_val_to_struct[i];
+ node = cladatum->constraints;
+
+ perdatum = (perm_datum_t *) hashtab_search(cladatum->permissions.table, (hashtab_key_t)
+ id);
+ if (!perdatum) {
+ if (cladatum->comdatum) {
+ perdatum = (perm_datum_t *)
+ hashtab_search(cladatum->comdatum->permissions.table, (hashtab_key_t)
+ id);
+ }
+ if (!perdatum) {
+ yyerror2("permission %s is not" " defined", id);
+ free(id);
+ ebitmap_destroy(&classmap);
+ return -1;
+ }
+ }
+ node->permissions |= (1 << (perdatum->s.value - 1));
+ }
+ }
+ free(id);
+ }
+
+ ebitmap_destroy(&classmap);
+
+ return 0;
+}
+
+int define_validatetrans(constraint_expr_t * expr)
+{
+ struct constraint_node *node;
+ char *id;
+ class_datum_t *cladatum;
+ ebitmap_t classmap;
+ constraint_expr_t *e;
+ int depth;
+ unsigned char useexpr = 1;
+
+ if (pass == 1) {
+ while ((id = queue_remove(id_queue)))
+ free(id);
+ return 0;
+ }
+
+ depth = -1;
+ for (e = expr; e; e = e->next) {
+ switch (e->expr_type) {
+ case CEXPR_NOT:
+ if (depth < 0) {
+ yyerror("illegal validatetrans expression");
+ return -1;
+ }
+ break;
+ case CEXPR_AND:
+ case CEXPR_OR:
+ if (depth < 1) {
+ yyerror("illegal validatetrans expression");
+ return -1;
+ }
+ depth--;
+ break;
+ case CEXPR_ATTR:
+ case CEXPR_NAMES:
+ if (depth == (CEXPR_MAXDEPTH - 1)) {
+ yyerror("validatetrans expression is too deep");
+ return -1;
+ }
+ depth++;
+ break;
+ default:
+ yyerror("illegal validatetrans expression");
+ return -1;
+ }
+ }
+ if (depth != 0) {
+ yyerror("illegal validatetrans expression");
+ return -1;
+ }
+
+ ebitmap_init(&classmap);
+ while ((id = queue_remove(id_queue))) {
+ if (!is_id_in_scope(SYM_CLASSES, id)) {
+ yyerror2("class %s is not within scope", id);
+ free(id);
+ return -1;
+ }
+ cladatum = (class_datum_t *) hashtab_search(policydbp->p_classes.table, (hashtab_key_t) id);
+ if (!cladatum) {
+ yyerror2("class %s is not defined", id);
+ ebitmap_destroy(&classmap);
+ free(id);
+ return -1;
+ }
+ if (ebitmap_set_bit(&classmap, (cladatum->s.value - 1), TRUE)) {
+ yyerror("out of memory");
+ ebitmap_destroy(&classmap);
+ free(id);
+ return -1;
+ }
+
+ node = malloc(sizeof(struct constraint_node));
+ if (!node) {
+ yyerror("out of memory");
+ return -1;
+ }
+ memset(node, 0, sizeof(constraint_node_t));
+ if (useexpr) {
+ node->expr = expr;
+ useexpr = 0;
+ } else {
+ node->expr = constraint_expr_clone(expr);
+ }
+ node->permissions = 0;
+
+ node->next = cladatum->validatetrans;
+ cladatum->validatetrans = node;
+
+ free(id);
+ }
+
+ ebitmap_destroy(&classmap);
+
+ return 0;
+}
+
+uintptr_t define_cexpr(uint32_t expr_type, uintptr_t arg1, uintptr_t arg2)
+{
+ struct constraint_expr *expr, *e1 = NULL, *e2;
+ user_datum_t *user;
+ role_datum_t *role;
+ ebitmap_t negset;
+ char *id;
+ uint32_t val;
+ int add = 1;
+
+ if (pass == 1) {
+ if (expr_type == CEXPR_NAMES) {
+ while ((id = queue_remove(id_queue)))
+ free(id);
+ }
+ return 1; /* any non-NULL value */
+ }
+
+ if ((expr = malloc(sizeof(*expr))) == NULL || constraint_expr_init(expr) == -1) {
+ yyerror("out of memory");
+ free(expr);
+ return 0;
+ }
+ expr->expr_type = expr_type;
+
+ switch (expr_type) {
+ case CEXPR_NOT:
+ e1 = NULL;
+ e2 = (struct constraint_expr *)arg1;
+ while (e2) {
+ e1 = e2;
+ e2 = e2->next;
+ }
+ if (!e1 || e1->next) {
+ yyerror("illegal constraint expression");
+ constraint_expr_destroy(expr);
+ return 0;
+ }
+ e1->next = expr;
+ return arg1;
+ case CEXPR_AND:
+ case CEXPR_OR:
+ e1 = NULL;
+ e2 = (struct constraint_expr *)arg1;
+ while (e2) {
+ e1 = e2;
+ e2 = e2->next;
+ }
+ if (!e1 || e1->next) {
+ yyerror("illegal constraint expression");
+ constraint_expr_destroy(expr);
+ return 0;
+ }
+ e1->next = (struct constraint_expr *)arg2;
+
+ e1 = NULL;
+ e2 = (struct constraint_expr *)arg2;
+ while (e2) {
+ e1 = e2;
+ e2 = e2->next;
+ }
+ if (!e1 || e1->next) {
+ yyerror("illegal constraint expression");
+ constraint_expr_destroy(expr);
+ return 0;
+ }
+ e1->next = expr;
+ return arg1;
+ case CEXPR_ATTR:
+ expr->attr = arg1;
+ expr->op = arg2;
+ return (uintptr_t) expr;
+ case CEXPR_NAMES:
+ add = 1;
+ expr->attr = arg1;
+ expr->op = arg2;
+ ebitmap_init(&negset);
+ while ((id = (char *)queue_remove(id_queue))) {
+ if (expr->attr & CEXPR_USER) {
+ if (!is_id_in_scope(SYM_USERS, id)) {
+ yyerror2("user %s is not within scope", id);
+ constraint_expr_destroy(expr);
+ return 0;
+ }
+ user = (user_datum_t *) hashtab_search(policydbp->p_users.table, (hashtab_key_t)
+ id);
+ if (!user) {
+ yyerror2("unknown user %s", id);
+ constraint_expr_destroy(expr);
+ return 0;
+ }
+ val = user->s.value;
+ } else if (expr->attr & CEXPR_ROLE) {
+ if (!is_id_in_scope(SYM_ROLES, id)) {
+ yyerror2("role %s is not within scope", id);
+ constraint_expr_destroy(expr);
+ return 0;
+ }
+ role = (role_datum_t *) hashtab_search(policydbp->p_roles.table, (hashtab_key_t)
+ id);
+ if (!role) {
+ yyerror2("unknown role %s", id);
+ constraint_expr_destroy(expr);
+ return 0;
+ }
+ val = role->s.value;
+ } else if (expr->attr & CEXPR_TYPE) {
+ if (set_types(expr->type_names, id, &add, 0)) {
+ constraint_expr_destroy(expr);
+ return 0;
+ }
+ continue;
+ } else {
+ yyerror("invalid constraint expression");
+ constraint_expr_destroy(expr);
+ return 0;
+ }
+ if (ebitmap_set_bit(&expr->names, val - 1, TRUE)) {
+ yyerror("out of memory");
+ ebitmap_destroy(&expr->names);
+ constraint_expr_destroy(expr);
+ return 0;
+ }
+ free(id);
+ }
+ ebitmap_destroy(&negset);
+ return (uintptr_t) expr;
+ default:
+ yyerror("invalid constraint expression");
+ constraint_expr_destroy(expr);
+ return 0;
+ }
+
+ yyerror("invalid constraint expression");
+ free(expr);
+ return 0;
+}
+
+int define_conditional(cond_expr_t * expr, avrule_t * t, avrule_t * f)
+{
+ cond_expr_t *e;
+ int depth, retval;
+ cond_node_t cn, *cn_old;
+ avrule_t *tmp, *last_tmp;
+
+ /* expression cannot be NULL */
+ if (!expr) {
+ yyerror("illegal conditional expression");
+ return -1;
+ }
+ if (!t) {
+ if (!f) {
+ /* empty is fine, destroy expression and return */
+ cond_expr_destroy(expr);
+ return 0;
+ }
+ /* Invert */
+ t = f;
+ f = 0;
+ expr = define_cond_expr(COND_NOT, expr, 0);
+ if (!expr) {
+ yyerror("unable to invert");
+ return -1;
+ }
+ }
+
+ /* verify expression */
+ depth = -1;
+ for (e = expr; e; e = e->next) {
+ switch (e->expr_type) {
+ case COND_NOT:
+ if (depth < 0) {
+ yyerror("illegal conditional expression; Bad NOT");
+ return -1;
+ }
+ break;
+ case COND_AND:
+ case COND_OR:
+ case COND_XOR:
+ case COND_EQ:
+ case COND_NEQ:
+ if (depth < 1) {
+ yyerror("illegal conditional expression; Bad binary op");
+ return -1;
+ }
+ depth--;
+ break;
+ case COND_BOOL:
+ if (depth == (COND_EXPR_MAXDEPTH - 1)) {
+ yyerror("conditional expression is like totally too deep");
+ return -1;
+ }
+ depth++;
+ break;
+ default:
+ yyerror("illegal conditional expression");
+ return -1;
+ }
+ }
+ if (depth != 0) {
+ yyerror("illegal conditional expression");
+ return -1;
+ }
+
+ /* use tmp conditional node to partially build new node */
+ memset(&cn, 0, sizeof(cn));
+ cn.expr = expr;
+ cn.avtrue_list = t;
+ cn.avfalse_list = f;
+
+ /* normalize/precompute expression */
+ if (cond_normalize_expr(policydbp, &cn) < 0) {
+ yyerror("problem normalizing conditional expression");
+ return -1;
+ }
+
+ /* get the existing conditional node, or create a new one */
+ cn_old = get_current_cond_list(&cn);
+ if (!cn_old) {
+ return -1;
+ }
+
+ /* verify te rules -- both true and false branches of conditional */
+ tmp = cn.avtrue_list;
+ last_tmp = NULL;
+ while (tmp) {
+ if (!tmp->specified & AVRULE_TRANSITION)
+ continue;
+ retval = insert_check_type_rule(tmp, &policydbp->te_cond_avtab, &cn_old->true_list, &cn_old->false_list);
+ switch (retval) {
+ case 1:{
+ last_tmp = tmp;
+ tmp = tmp->next;
+ break;
+ }
+ case 0:{
+ /* rule conflicted, so remove it from consideration */
+ if (last_tmp == NULL) {
+ cn.avtrue_list = cn.avtrue_list->next;
+ avrule_destroy(tmp);
+ free(tmp);
+ tmp = cn.avtrue_list;
+ } else {
+ last_tmp->next = tmp->next;
+ avrule_destroy(tmp);
+ free(tmp);
+ tmp = last_tmp->next;
+ }
+ break;
+ }
+ case -1:{
+ return -1;
+ }
+ case 2:{
+ return 0;
+ }
+ default:{
+ assert(0); /* should never get here */
+ }
+ }
+ }
+
+ tmp = cn.avfalse_list;
+ last_tmp = NULL;
+ while (tmp) {
+ if (!tmp->specified & AVRULE_TRANSITION)
+ continue;
+ retval = insert_check_type_rule(tmp, &policydbp->te_cond_avtab, &cn_old->false_list, &cn_old->true_list);
+ switch (retval) {
+ case 1:{
+ last_tmp = tmp;
+ tmp = tmp->next;
+ break;
+ }
+ case 0:{
+ /* rule conflicted, so remove it from consideration */
+ if (last_tmp == NULL) {
+ cn.avfalse_list = cn.avfalse_list->next;
+ avrule_destroy(tmp);
+ free(tmp);
+ tmp = cn.avfalse_list;
+ } else {
+ last_tmp->next = tmp->next;
+ avrule_destroy(tmp);
+ free(tmp);
+ tmp = last_tmp->next;
+ }
+ break;
+ }
+ case -1:{
+ return -1;
+ }
+ case 2:{
+ return 0;
+ }
+ default:{
+ assert(0); /* should never get here */
+ }
+ }
+ }
+
+ append_cond_list(&cn);
+
+ /* note that there is no check here for duplicate rules, nor
+ * check that rule already exists in base -- that will be
+ * handled during conditional expansion, in expand.c */
+
+ cn.avtrue_list = NULL;
+ cn.avfalse_list = NULL;
+ cond_node_destroy(&cn);
+
+ return 0;
+}
+
+cond_expr_t *define_cond_expr(uint32_t expr_type, void *arg1, void *arg2)
+{
+ struct cond_expr *expr, *e1 = NULL, *e2;
+ cond_bool_datum_t *bool_var;
+ char *id;
+
+ /* expressions are handled in the second pass */
+ if (pass == 1) {
+ if (expr_type == COND_BOOL) {
+ while ((id = queue_remove(id_queue))) {
+ free(id);
+ }
+ }
+ return (cond_expr_t *) 1; /* any non-NULL value */
+ }
+
+ /* create a new expression struct */
+ expr = malloc(sizeof(struct cond_expr));
+ if (!expr) {
+ yyerror("out of memory");
+ return NULL;
+ }
+ memset(expr, 0, sizeof(cond_expr_t));
+ expr->expr_type = expr_type;
+
+ /* create the type asked for */
+ switch (expr_type) {
+ case COND_NOT:
+ e1 = NULL;
+ e2 = (struct cond_expr *)arg1;
+ while (e2) {
+ e1 = e2;
+ e2 = e2->next;
+ }
+ if (!e1 || e1->next) {
+ yyerror("illegal conditional NOT expression");
+ free(expr);
+ return NULL;
+ }
+ e1->next = expr;
+ return (struct cond_expr *)arg1;
+ case COND_AND:
+ case COND_OR:
+ case COND_XOR:
+ case COND_EQ:
+ case COND_NEQ:
+ e1 = NULL;
+ e2 = (struct cond_expr *)arg1;
+ while (e2) {
+ e1 = e2;
+ e2 = e2->next;
+ }
+ if (!e1 || e1->next) {
+ yyerror("illegal left side of conditional binary op expression");
+ free(expr);
+ return NULL;
+ }
+ e1->next = (struct cond_expr *)arg2;
+
+ e1 = NULL;
+ e2 = (struct cond_expr *)arg2;
+ while (e2) {
+ e1 = e2;
+ e2 = e2->next;
+ }
+ if (!e1 || e1->next) {
+ yyerror("illegal right side of conditional binary op expression");
+ free(expr);
+ return NULL;
+ }
+ e1->next = expr;
+ return (struct cond_expr *)arg1;
+ case COND_BOOL:
+ id = (char *)queue_remove(id_queue);
+ if (!id) {
+ yyerror("bad conditional; expected boolean id");
+ free(id);
+ free(expr);
+ return NULL;
+ }
+ if (!is_id_in_scope(SYM_BOOLS, id)) {
+ yyerror2("boolean %s is not within scope", id);
+ free(id);
+ free(expr);
+ return NULL;
+ }
+ bool_var = (cond_bool_datum_t *) hashtab_search(policydbp->p_bools.table, (hashtab_key_t) id);
+ if (!bool_var) {
+ yyerror2("unknown boolean %s in conditional expression", id);
+ free(expr);
+ free(id);
+ return NULL;
+ }
+ expr->bool = bool_var->s.value;
+ free(id);
+ return expr;
+ default:
+ yyerror("illegal conditional expression");
+ return NULL;
+ }
+}
+
+static int set_user_roles(role_set_t * set, char *id)
+{
+ role_datum_t *r;
+ unsigned int i;
+ ebitmap_node_t *node;
+
+ if (strcmp(id, "*") == 0) {
+ free(id);
+ yyerror("* is not allowed in user declarations");
+ return -1;
+ }
+
+ if (strcmp(id, "~") == 0) {
+ free(id);
+ yyerror("~ is not allowed in user declarations");
+ return -1;
+ }
+
+ if (!is_id_in_scope(SYM_ROLES, id)) {
+ yyerror2("role %s is not within scope", id);
+ free(id);
+ return -1;
+ }
+ r = hashtab_search(policydbp->p_roles.table, id);
+ if (!r) {
+ yyerror2("unknown role %s", id);
+ free(id);
+ return -1;
+ }
+
+ /* set the role and every role it dominates */
+ ebitmap_for_each_bit(&r->dominates, node, i) {
+ if (ebitmap_node_get_bit(node, i))
+ if (ebitmap_set_bit(&set->roles, i, TRUE))
+ goto oom;
+ }
+ free(id);
+ return 0;
+ oom:
+ yyerror("out of memory");
+ return -1;
+}
+
+static int parse_categories(char *id, level_datum_t * levdatum, ebitmap_t * cats)
+{
+ cat_datum_t *cdatum;
+ int range_start, range_end, i;
+
+ if (id_has_dot(id)) {
+ char *id_start = id;
+ char *id_end = strchr(id, '.');
+
+ *(id_end++) = '\0';
+
+ cdatum = (cat_datum_t *) hashtab_search(policydbp->p_cats.table, (hashtab_key_t)
+ id_start);
+ if (!cdatum) {
+ yyerror2("unknown category %s", id_start);
+ return -1;
+ }
+ range_start = cdatum->s.value - 1;
+ cdatum = (cat_datum_t *) hashtab_search(policydbp->p_cats.table, (hashtab_key_t) id_end);
+ if (!cdatum) {
+ yyerror2("unknown category %s", id_end);
+ return -1;
+ }
+ range_end = cdatum->s.value - 1;
+
+ if (range_end < range_start) {
+ yyerror2("category range is invalid");
+ return -1;
+ }
+ } else {
+ cdatum = (cat_datum_t *) hashtab_search(policydbp->p_cats.table, (hashtab_key_t) id);
+ if (!cdatum) {
+ yyerror2("unknown category %s", id);
+ return -1;
+ }
+ range_start = range_end = cdatum->s.value - 1;
+ }
+
+ for (i = range_start; i <= range_end; i++) {
+ if (!ebitmap_get_bit(&levdatum->level->cat, i)) {
+ uint32_t level_value = levdatum->level->sens - 1;
+ policydb_index_others(NULL, policydbp, 0);
+ yyerror2("category %s can not be associated "
+ "with level %s", policydbp->p_cat_val_to_name[i], policydbp->p_sens_val_to_name[level_value]);
+ return -1;
+ }
+ if (ebitmap_set_bit(cats, i, TRUE)) {
+ yyerror("out of memory");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int parse_semantic_categories(char *id, level_datum_t * levdatum, mls_semantic_cat_t ** cats)
+{
+ cat_datum_t *cdatum;
+ mls_semantic_cat_t *newcat;
+ unsigned int range_start, range_end;
+
+ if (id_has_dot(id)) {
+ char *id_start = id;
+ char *id_end = strchr(id, '.');
+
+ *(id_end++) = '\0';
+
+ cdatum = (cat_datum_t *) hashtab_search(policydbp->p_cats.table, (hashtab_key_t)
+ id_start);
+ if (!cdatum) {
+ yyerror2("unknown category %s", id_start);
+ return -1;
+ }
+ range_start = cdatum->s.value;
+
+ cdatum = (cat_datum_t *) hashtab_search(policydbp->p_cats.table, (hashtab_key_t) id_end);
+ if (!cdatum) {
+ yyerror2("unknown category %s", id_end);
+ return -1;
+ }
+ range_end = cdatum->s.value;
+ } else {
+ cdatum = (cat_datum_t *) hashtab_search(policydbp->p_cats.table, (hashtab_key_t) id);
+ if (!cdatum) {
+ yyerror2("unknown category %s", id);
+ return -1;
+ }
+ range_start = range_end = cdatum->s.value;
+ }
+
+ newcat = (mls_semantic_cat_t *) malloc(sizeof(mls_semantic_cat_t));
+ if (!newcat) {
+ yyerror("out of memory");
+ return -1;
+ }
+
+ mls_semantic_cat_init(newcat);
+ newcat->next = *cats;
+ newcat->low = range_start;
+ newcat->high = range_end;
+
+ *cats = newcat;
+
+ return 0;
+}
+
+int define_user(void)
+{
+ char *id;
+ user_datum_t *usrdatum;
+ level_datum_t *levdatum;
+ int l;
+
+ if (pass == 1) {
+ while ((id = queue_remove(id_queue)))
+ free(id);
+ if (mlspol) {
+ while ((id = queue_remove(id_queue)))
+ free(id);
+ id = queue_remove(id_queue);
+ free(id);
+ for (l = 0; l < 2; l++) {
+ while ((id = queue_remove(id_queue))) {
+ free(id);
+ }
+ id = queue_remove(id_queue);
+ if (!id)
+ break;
+ free(id);
+ }
+ }
+ return 0;
+ }
+
+ if ((usrdatum = declare_user()) == NULL) {
+ return -1;
+ }
+
+ while ((id = queue_remove(id_queue))) {
+ if (set_user_roles(&usrdatum->roles, id))
+ continue;
+ }
+
+ if (mlspol) {
+ id = queue_remove(id_queue);
+ if (!id) {
+ yyerror("no default level specified for user");
+ return -1;
+ }
+
+ levdatum = (level_datum_t *)
+ hashtab_search(policydbp->p_levels.table, (hashtab_key_t) id);
+ if (!levdatum) {
+ yyerror2("unknown sensitivity %s used in user" " level definition", id);
+ free(id);
+ return -1;
+ }
+ free(id);
+
+ usrdatum->dfltlevel.sens = levdatum->level->sens;
+
+ while ((id = queue_remove(id_queue))) {
+ if (parse_semantic_categories(id, levdatum, &usrdatum->dfltlevel.cat)) {
+ free(id);
+ return -1;
+ }
+ free(id);
+ }
+
+ id = queue_remove(id_queue);
+
+ for (l = 0; l < 2; l++) {
+ levdatum = (level_datum_t *)
+ hashtab_search(policydbp->p_levels.table, (hashtab_key_t) id);
+ if (!levdatum) {
+ yyerror2("unknown sensitivity %s used in user" " range definition", id);
+ free(id);
+ return -1;
+ }
+ free(id);
+
+ usrdatum->range.level[l].sens = levdatum->level->sens;
+
+ while ((id = queue_remove(id_queue))) {
+ if (parse_semantic_categories(id, levdatum, &usrdatum->range.level[l].cat)) {
+ free(id);
+ return -1;
+ }
+ free(id);
+ }
+
+ id = queue_remove(id_queue);
+ if (!id)
+ break;
+ }
+
+ if (l == 0) {
+ if (mls_semantic_level_cpy(&usrdatum->range.level[1], &usrdatum->range.level[0])) {
+ yyerror("out of memory");
+ return -1;
+ }
+ }
+ }
+ return 0;
+}
+
+static int parse_security_context(context_struct_t * c)
+{
+ char *id;
+ role_datum_t *role;
+ type_datum_t *typdatum;
+ user_datum_t *usrdatum;
+ level_datum_t *levdatum;
+ int l;
+
+ if (pass == 1) {
+ id = queue_remove(id_queue);
+ free(id); /* user */
+ id = queue_remove(id_queue);
+ free(id); /* role */
+ id = queue_remove(id_queue);
+ free(id); /* type */
+ if (mlspol) {
+ id = queue_remove(id_queue);
+ free(id);
+ for (l = 0; l < 2; l++) {
+ while ((id = queue_remove(id_queue))) {
+ free(id);
+ }
+ id = queue_remove(id_queue);
+ if (!id)
+ break;
+ free(id);
+ }
+ }
+ return 0;
+ }
+
+ context_init(c);
+
+ /* extract the user */
+ id = queue_remove(id_queue);
+ if (!id) {
+ yyerror("no effective user?");
+ goto bad;
+ }
+ if (!is_id_in_scope(SYM_USERS, id)) {
+ yyerror2("user %s is not within scope", id);
+ free(id);
+ goto bad;
+ }
+ usrdatum = (user_datum_t *) hashtab_search(policydbp->p_users.table, (hashtab_key_t) id);
+ if (!usrdatum) {
+ yyerror2("user %s is not defined", id);
+ free(id);
+ goto bad;
+ }
+ c->user = usrdatum->s.value;
+
+ /* no need to keep the user name */
+ free(id);
+
+ /* extract the role */
+ id = (char *)queue_remove(id_queue);
+ if (!id) {
+ yyerror("no role name for sid context definition?");
+ return -1;
+ }
+ if (!is_id_in_scope(SYM_ROLES, id)) {
+ yyerror2("role %s is not within scope", id);
+ free(id);
+ return -1;
+ }
+ role = (role_datum_t *) hashtab_search(policydbp->p_roles.table, (hashtab_key_t) id);
+ if (!role) {
+ yyerror2("role %s is not defined", id);
+ free(id);
+ return -1;
+ }
+ c->role = role->s.value;
+
+ /* no need to keep the role name */
+ free(id);
+
+ /* extract the type */
+ id = (char *)queue_remove(id_queue);
+ if (!id) {
+ yyerror("no type name for sid context definition?");
+ return -1;
+ }
+ if (!is_id_in_scope(SYM_TYPES, id)) {
+ yyerror2("type %s is not within scope", id);
+ free(id);
+ return -1;
+ }
+ typdatum = (type_datum_t *) hashtab_search(policydbp->p_types.table, (hashtab_key_t) id);
+ if (!typdatum || typdatum->flavor == TYPE_ATTRIB) {
+ yyerror2("type %s is not defined or is an attribute", id);
+ free(id);
+ return -1;
+ }
+ c->type = typdatum->s.value;
+
+ /* no need to keep the type name */
+ free(id);
+
+ if (mlspol) {
+ /* extract the low sensitivity */
+ id = (char *)queue_head(id_queue);
+ if (!id) {
+ yyerror("no sensitivity name for sid context" " definition?");
+ return -1;
+ }
+
+ id = (char *)queue_remove(id_queue);
+ for (l = 0; l < 2; l++) {
+ levdatum = (level_datum_t *)
+ hashtab_search(policydbp->p_levels.table, (hashtab_key_t) id);
+ if (!levdatum) {
+ yyerror2("Sensitivity %s is not defined", id);
+ free(id);
+ return -1;
+ }
+ free(id);
+ c->range.level[l].sens = levdatum->level->sens;
+
+ /* extract low category set */
+ while ((id = queue_remove(id_queue))) {
+ if (parse_categories(id, levdatum, &c->range.level[l].cat)) {
+ free(id);
+ return -1;
+ }
+ free(id);
+ }
+
+ /* extract high sensitivity */
+ id = (char *)queue_remove(id_queue);
+ if (!id)
+ break;
+ }
+
+ if (l == 0) {
+ c->range.level[1].sens = c->range.level[0].sens;
+ if (ebitmap_cpy(&c->range.level[1].cat, &c->range.level[0].cat)) {
+
+ yyerror("out of memory");
+ goto bad;
+ }
+ }
+ }
+
+ if (!policydb_context_isvalid(policydbp, c)) {
+ yyerror("invalid security context");
+ goto bad;
+ }
+ return 0;
+
+ bad:
+ context_destroy(c);
+
+ return -1;
+}
+
+int define_initial_sid_context(void)
+{
+ char *id;
+ ocontext_t *c, *head;
+
+ if (pass == 1) {
+ id = (char *)queue_remove(id_queue);
+ free(id);
+ parse_security_context(NULL);
+ return 0;
+ }
+
+ id = (char *)queue_remove(id_queue);
+ if (!id) {
+ yyerror("no sid name for SID context definition?");
+ return -1;
+ }
+ head = policydbp->ocontexts[OCON_ISID];
+ for (c = head; c; c = c->next) {
+ if (!strcmp(id, c->u.name))
+ break;
+ }
+
+ if (!c) {
+ yyerror2("SID %s is not defined", id);
+ free(id);
+ return -1;
+ }
+ if (c->context[0].user) {
+ yyerror2("The context for SID %s is multiply defined", id);
+ free(id);
+ return -1;
+ }
+ /* no need to keep the sid name */
+ free(id);
+
+ if (parse_security_context(&c->context[0]))
+ return -1;
+
+ return 0;
+}
+
+int define_fs_context(unsigned int major, unsigned int minor)
+{
+ ocontext_t *newc, *c, *head;
+
+#ifdef SEPOL_TARGET_XEN
+ if (policydbp->target_platform != SEPOL_TARGET_SELINUX) {
+ yyerror("fscon not supported for target");
+ return -1;
+ }
+#endif
+
+ if (pass == 1) {
+ parse_security_context(NULL);
+ parse_security_context(NULL);
+ return 0;
+ }
+
+ newc = (ocontext_t *) malloc(sizeof(ocontext_t));
+ if (!newc) {
+ yyerror("out of memory");
+ return -1;
+ }
+ memset(newc, 0, sizeof(ocontext_t));
+
+ newc->u.name = (char *)malloc(6);
+ if (!newc->u.name) {
+ yyerror("out of memory");
+ free(newc);
+ return -1;
+ }
+ sprintf(newc->u.name, "%02x:%02x", major, minor);
+
+ if (parse_security_context(&newc->context[0])) {
+ free(newc->u.name);
+ free(newc);
+ return -1;
+ }
+ if (parse_security_context(&newc->context[1])) {
+ context_destroy(&newc->context[0]);
+ free(newc->u.name);
+ free(newc);
+ return -1;
+ }
+ head = policydbp->ocontexts[OCON_FS];
+
+ for (c = head; c; c = c->next) {
+ if (!strcmp(newc->u.name, c->u.name)) {
+ yyerror2("duplicate entry for file system %s", newc->u.name);
+ context_destroy(&newc->context[0]);
+ context_destroy(&newc->context[1]);
+ free(newc->u.name);
+ free(newc);
+ return -1;
+ }
+ }
+
+ newc->next = head;
+ policydbp->ocontexts[OCON_FS] = newc;
+
+ return 0;
+}
+
+int define_pirq_context(unsigned int pirq)
+{
+ ocontext_t *newc, *c, *l, *head;
+ char *id;
+
+#ifndef SEPOL_TARGET_XEN
+ yyerror("pirqcon not supported for target");
+ return -1;
+#else
+ if (policydbp->target_platform != SEPOL_TARGET_XEN) {
+ yyerror("pirqcon not supported for target");
+ return -1;
+ }
+
+ if (pass == 1) {
+ id = (char *)queue_remove(id_queue);
+ free(id);
+ parse_security_context(NULL);
+ return 0;
+ }
+
+ newc = malloc(sizeof(ocontext_t));
+ if (!newc) {
+ yyerror("out of memory");
+ return -1;
+ }
+ memset(newc, 0, sizeof(ocontext_t));
+
+ newc->u.pirq = pirq;
+
+ if (parse_security_context(&newc->context[0])) {
+ free(newc);
+ return -1;
+ }
+
+ head = policydbp->ocontexts[OCON_XEN_PIRQ];
+ for (l = NULL, c = head; c; l = c, c = c->next) {
+ unsigned int pirq2;
+
+ pirq2 = c->u.pirq;
+ if (pirq == pirq2) {
+ yyerror2("duplicate pirqcon entry for %d ", pirq);
+ goto bad;
+ }
+ }
+
+ if (l)
+ l->next = newc;
+ else
+ policydbp->ocontexts[OCON_XEN_PIRQ] = newc;
+
+ return 0;
+
+ bad:
+ free(newc);
+ return -1;
+#endif
+}
+
+int define_iomem_context(unsigned long low, unsigned long high)
+{
+ ocontext_t *newc, *c, *l, *head;
+ char *id;
+
+#ifndef SEPOL_TARGET_XEN
+ yyerror("iomemcon not supported for target");
+ return -1;
+#else
+ if (policydbp->target_platform != SEPOL_TARGET_XEN) {
+ yyerror("iomemcon not supported for target");
+ return -1;
+ }
+
+ if (pass == 1) {
+ id = (char *)queue_remove(id_queue);
+ free(id);
+ parse_security_context(NULL);
+ return 0;
+ }
+
+ newc = malloc(sizeof(ocontext_t));
+ if (!newc) {
+ yyerror("out of memory");
+ return -1;
+ }
+ memset(newc, 0, sizeof(ocontext_t));
+
+ newc->u.iomem.low_iomem = low;
+ newc->u.iomem.high_iomem = high;
+
+ if (low > high) {
+ yyerror2("low memory 0x%x exceeds high memory 0x%x", low, high);
+ free(newc);
+ return -1;
+ }
+
+ if (parse_security_context(&newc->context[0])) {
+ free(newc);
+ return -1;
+ }
+
+ head = policydbp->ocontexts[OCON_XEN_IOMEM];
+ for (l = NULL, c = head; c; l = c, c = c->next) {
+ unsigned int low2, high2;
+
+ low2 = c->u.iomem.low_iomem;
+ high2 = c->u.iomem.high_iomem;
+ if (low <= high2 && low2 <= high) {
+ yyerror2("iomemcon entry for 0x%x-0x%x overlaps with " "earlier entry 0x%x-0x%x", low, high, low2, high2);
+ goto bad;
+ }
+ }
+
+ if (l)
+ l->next = newc;
+ else
+ policydbp->ocontexts[OCON_XEN_IOMEM] = newc;
+
+ return 0;
+
+ bad:
+ free(newc);
+ return -1;
+#endif
+}
+
+int define_ioport_context(unsigned long low, unsigned long high)
+{
+ ocontext_t *newc, *c, *l, *head;
+ char *id;
+
+#ifndef SEPOL_TARGET_XEN
+ yyerror("ioportcon not supported for target");
+ return -1;
+#else
+ if (policydbp->target_platform != SEPOL_TARGET_XEN) {
+ yyerror("ioportcon not supported for target");
+ return -1;
+ }
+
+ if (pass == 1) {
+ id = (char *)queue_remove(id_queue);
+ free(id);
+ parse_security_context(NULL);
+ return 0;
+ }
+
+ newc = malloc(sizeof(ocontext_t));
+ if (!newc) {
+ yyerror("out of memory");
+ return -1;
+ }
+ memset(newc, 0, sizeof(ocontext_t));
+
+ newc->u.ioport.low_ioport = low;
+ newc->u.ioport.high_ioport = high;
+
+ if (low > high) {
+ yyerror2("low ioport 0x%x exceeds high ioport 0x%x", low, high);
+ free(newc);
+ return -1;
+ }
+
+ if (parse_security_context(&newc->context[0])) {
+ free(newc);
+ return -1;
+ }
+
+ head = policydbp->ocontexts[OCON_XEN_IOPORT];
+ for (l = NULL, c = head; c; l = c, c = c->next) {
+ unsigned int low2, high2;
+
+ low2 = c->u.ioport.low_ioport;
+ high2 = c->u.ioport.high_ioport;
+ if (low <= high2 && low2 <= high) {
+ yyerror2("ioportcon entry for 0x%x-0x%x overlaps with" "earlier entry 0x%x-0x%x", low, high, low2, high2);
+ goto bad;
+ }
+ }
+
+ if (l)
+ l->next = newc;
+ else
+ policydbp->ocontexts[OCON_XEN_IOPORT] = newc;
+
+ return 0;
+
+ bad:
+ free(newc);
+ return -1;
+#endif
+}
+
+int define_pcidevice_context(unsigned long device)
+{
+ ocontext_t *newc, *c, *l, *head;
+ char *id;
+
+#ifndef SEPOL_TARGET_XEN
+ yyerror("pcidevicecon not supported for target");
+ return -1;
+#else
+ if (policydbp->target_platform != SEPOL_TARGET_XEN) {
+ yyerror("pcidevicecon not supported for target");
+ return -1;
+ }
+
+ if (pass == 1) {
+ id = (char *)queue_remove(id_queue);
+ free(id);
+ parse_security_context(NULL);
+ return 0;
+ }
+
+ newc = malloc(sizeof(ocontext_t));
+ if (!newc) {
+ yyerror("out of memory");
+ return -1;
+ }
+ memset(newc, 0, sizeof(ocontext_t));
+
+ newc->u.device = device;
+
+ if (parse_security_context(&newc->context[0])) {
+ free(newc);
+ return -1;
+ }
+
+ head = policydbp->ocontexts[OCON_XEN_PCIDEVICE];
+ for (l = NULL, c = head; c; l = c, c = c->next) {
+ unsigned int device2;
+
+ device2 = c->u.device;
+ if (device == device2) {
+ yyerror2("duplicate pcidevicecon entry for 0x%x ", device);
+ goto bad;
+ }
+ }
+
+ if (l)
+ l->next = newc;
+ else
+ policydbp->ocontexts[OCON_XEN_PCIDEVICE] = newc;
+
+ return 0;
+
+ bad:
+ free(newc);
+ return -1;
+#endif
+}
+
+int define_port_context(unsigned int low, unsigned int high)
+{
+ ocontext_t *newc, *c, *l, *head;
+ unsigned int protocol;
+ char *id;
+
+#ifdef SEPOL_TARGET_XEN
+ if (policydbp->target_platform != SEPOL_TARGET_SELINUX) {
+ yyerror("portcon not supported for target");
+ return -1;
+ }
+#endif
+
+ if (pass == 1) {
+ id = (char *)queue_remove(id_queue);
+ free(id);
+ parse_security_context(NULL);
+ return 0;
+ }
+
+ newc = malloc(sizeof(ocontext_t));
+ if (!newc) {
+ yyerror("out of memory");
+ return -1;
+ }
+ memset(newc, 0, sizeof(ocontext_t));
+
+ id = (char *)queue_remove(id_queue);
+ if (!id) {
+ free(newc);
+ return -1;
+ }
+ if ((strcmp(id, "tcp") == 0) || (strcmp(id, "TCP") == 0)) {
+ protocol = IPPROTO_TCP;
+ } else if ((strcmp(id, "udp") == 0) || (strcmp(id, "UDP") == 0)) {
+ protocol = IPPROTO_UDP;
+ } else {
+ yyerror2("unrecognized protocol %s", id);
+ free(newc);
+ return -1;
+ }
+
+ newc->u.port.protocol = protocol;
+ newc->u.port.low_port = low;
+ newc->u.port.high_port = high;
+
+ if (low > high) {
+ yyerror2("low port %d exceeds high port %d", low, high);
+ free(newc);
+ return -1;
+ }
+
+ if (parse_security_context(&newc->context[0])) {
+ free(newc);
+ return -1;
+ }
+
+ /* Preserve the matching order specified in the configuration. */
+ head = policydbp->ocontexts[OCON_PORT];
+ for (l = NULL, c = head; c; l = c, c = c->next) {
+ unsigned int prot2, low2, high2;
+
+ prot2 = c->u.port.protocol;
+ low2 = c->u.port.low_port;
+ high2 = c->u.port.high_port;
+ if (protocol != prot2)
+ continue;
+ if (low == low2 && high == high2) {
+ yyerror2("duplicate portcon entry for %s %d-%d ", id, low, high);
+ goto bad;
+ }
+ if (low2 <= low && high2 >= high) {
+ yyerror2("portcon entry for %s %d-%d hidden by earlier " "entry for %d-%d", id, low, high, low2, high2);
+ goto bad;
+ }
+ }
+ free(id);
+
+ if (l)
+ l->next = newc;
+ else
+ policydbp->ocontexts[OCON_PORT] = newc;
+
+ return 0;
+
+ bad:
+ free(newc);
+ return -1;
+}
+
+int define_netif_context(void)
+{
+ ocontext_t *newc, *c, *head;
+
+#ifdef SEPOL_TARGET_XEN
+ if (policydbp->target_platform != SEPOL_TARGET_SELINUX) {
+ yyerror("netifcon not supported for target");
+ return -1;
+ }
+#endif
+
+ if (pass == 1) {
+ free(queue_remove(id_queue));
+ parse_security_context(NULL);
+ parse_security_context(NULL);
+ return 0;
+ }
+
+ newc = (ocontext_t *) malloc(sizeof(ocontext_t));
+ if (!newc) {
+ yyerror("out of memory");
+ return -1;
+ }
+ memset(newc, 0, sizeof(ocontext_t));
+
+ newc->u.name = (char *)queue_remove(id_queue);
+ if (!newc->u.name) {
+ free(newc);
+ return -1;
+ }
+ if (parse_security_context(&newc->context[0])) {
+ free(newc->u.name);
+ free(newc);
+ return -1;
+ }
+ if (parse_security_context(&newc->context[1])) {
+ context_destroy(&newc->context[0]);
+ free(newc->u.name);
+ free(newc);
+ return -1;
+ }
+ head = policydbp->ocontexts[OCON_NETIF];
+
+ for (c = head; c; c = c->next) {
+ if (!strcmp(newc->u.name, c->u.name)) {
+ yyerror2("duplicate entry for network interface %s", newc->u.name);
+ context_destroy(&newc->context[0]);
+ context_destroy(&newc->context[1]);
+ free(newc->u.name);
+ free(newc);
+ return -1;
+ }
+ }
+
+ newc->next = head;
+ policydbp->ocontexts[OCON_NETIF] = newc;
+ return 0;
+}
+
+int define_ipv4_node_context()
+{
+ char *id;
+ int rc = 0;
+ struct in_addr addr, mask;
+ ocontext_t *newc, *c, *l, *head;
+
+#ifdef SEPOL_TARGET_XEN
+ if (policydbp->target_platform != SEPOL_TARGET_SELINUX) {
+ yyerror("nodecon not supported for target");
+ return -1;
+ }
+#endif
+
+ if (pass == 1) {
+ free(queue_remove(id_queue));
+ free(queue_remove(id_queue));
+ parse_security_context(NULL);
+ goto out;
+ }
+
+ id = queue_remove(id_queue);
+ if (!id) {
+ yyerror("failed to read ipv4 address");
+ rc = -1;
+ goto out;
+ }
+
+ rc = inet_pton(AF_INET, id, &addr);
+ free(id);
+ if (rc < 1) {
+ yyerror("failed to parse ipv4 address");
+ if (rc == 0)
+ rc = -1;
+ goto out;
+ }
+
+ id = queue_remove(id_queue);
+ if (!id) {
+ yyerror("failed to read ipv4 address");
+ rc = -1;
+ goto out;
+ }
+
+ rc = inet_pton(AF_INET, id, &mask);
+ free(id);
+ if (rc < 1) {
+ yyerror("failed to parse ipv4 mask");
+ if (rc == 0)
+ rc = -1;
+ goto out;
+ }
+
+ newc = malloc(sizeof(ocontext_t));
+ if (!newc) {
+ yyerror("out of memory");
+ rc = -1;
+ goto out;
+ }
+
+ memset(newc, 0, sizeof(ocontext_t));
+ newc->u.node.addr = addr.s_addr;
+ newc->u.node.mask = mask.s_addr;
+
+ if (parse_security_context(&newc->context[0])) {
+ free(newc);
+ return -1;
+ }
+
+ /* Create order of most specific to least retaining
+ the order specified in the configuration. */
+ head = policydbp->ocontexts[OCON_NODE];
+ for (l = NULL, c = head; c; l = c, c = c->next) {
+ if (newc->u.node.mask > c->u.node.mask)
+ break;
+ }
+
+ newc->next = c;
+
+ if (l)
+ l->next = newc;
+ else
+ policydbp->ocontexts[OCON_NODE] = newc;
+ rc = 0;
+ out:
+ return rc;
+}
+
+int define_ipv6_node_context(void)
+{
+ char *id;
+ int rc = 0;
+ struct in6_addr addr, mask;
+ ocontext_t *newc, *c, *l, *head;
+
+#ifdef SEPOL_TARGET_XEN
+ if (policydbp->target_platform != SEPOL_TARGET_SELINUX) {
+ yyerror("nodecon not supported for target");
+ return -1;
+ }
+#endif
+
+ if (pass == 1) {
+ free(queue_remove(id_queue));
+ free(queue_remove(id_queue));
+ parse_security_context(NULL);
+ goto out;
+ }
+
+ id = queue_remove(id_queue);
+ if (!id) {
+ yyerror("failed to read ipv6 address");
+ rc = -1;
+ goto out;
+ }
+
+ rc = inet_pton(AF_INET6, id, &addr);
+ free(id);
+ if (rc < 1) {
+ yyerror("failed to parse ipv6 address");
+ if (rc == 0)
+ rc = -1;
+ goto out;
+ }
+
+ id = queue_remove(id_queue);
+ if (!id) {
+ yyerror("failed to read ipv6 address");
+ rc = -1;
+ goto out;
+ }
+
+ rc = inet_pton(AF_INET6, id, &mask);
+ free(id);
+ if (rc < 1) {
+ yyerror("failed to parse ipv6 mask");
+ if (rc == 0)
+ rc = -1;
+ goto out;
+ }
+
+ newc = malloc(sizeof(ocontext_t));
+ if (!newc) {
+ yyerror("out of memory");
+ rc = -1;
+ goto out;
+ }
+
+ memset(newc, 0, sizeof(ocontext_t));
+ memcpy(&newc->u.node6.addr[0], &addr.s6_addr32[0], 16);
+ memcpy(&newc->u.node6.mask[0], &mask.s6_addr32[0], 16);
+
+ if (parse_security_context(&newc->context[0])) {
+ free(newc);
+ rc = -1;
+ goto out;
+ }
+
+ /* Create order of most specific to least retaining
+ the order specified in the configuration. */
+ head = policydbp->ocontexts[OCON_NODE6];
+ for (l = NULL, c = head; c; l = c, c = c->next) {
+ if (memcmp(&newc->u.node6.mask, &c->u.node6.mask, 16) > 0)
+ break;
+ }
+
+ newc->next = c;
+
+ if (l)
+ l->next = newc;
+ else
+ policydbp->ocontexts[OCON_NODE6] = newc;
+
+ rc = 0;
+ out:
+ return rc;
+}
+
+int define_fs_use(int behavior)
+{
+ ocontext_t *newc, *c, *head;
+
+#ifdef SEPOL_TARGET_XEN
+ if (policydbp->target_platform != SEPOL_TARGET_SELINUX) {
+ yyerror("fsuse not supported for target");
+ return -1;
+ }
+#endif
+
+ if (pass == 1) {
+ free(queue_remove(id_queue));
+ if (behavior != SECURITY_FS_USE_PSIDS)
+ parse_security_context(NULL);
+ return 0;
+ }
+
+ newc = (ocontext_t *) malloc(sizeof(ocontext_t));
+ if (!newc) {
+ yyerror("out of memory");
+ return -1;
+ }
+ memset(newc, 0, sizeof(ocontext_t));
+
+ newc->u.name = (char *)queue_remove(id_queue);
+ if (!newc->u.name) {
+ free(newc);
+ return -1;
+ }
+ newc->v.behavior = behavior;
+ if (newc->v.behavior != SECURITY_FS_USE_PSIDS) {
+ if (parse_security_context(&newc->context[0])) {
+ free(newc->u.name);
+ free(newc);
+ return -1;
+ }
+ } else
+ memset(&newc->context[0], 0, sizeof(context_struct_t) * 2);
+
+ head = policydbp->ocontexts[OCON_FSUSE];
+
+ for (c = head; c; c = c->next) {
+ if (!strcmp(newc->u.name, c->u.name)) {
+ yyerror2("duplicate fs_use entry for filesystem type %s", newc->u.name);
+ context_destroy(&newc->context[0]);
+ free(newc->u.name);
+ free(newc);
+ return -1;
+ }
+ }
+
+ newc->next = head;
+ policydbp->ocontexts[OCON_FSUSE] = newc;
+ return 0;
+}
+
+int define_genfs_context_helper(char *fstype, int has_type)
+{
+ struct genfs *genfs_p, *genfs, *newgenfs;
+ ocontext_t *newc, *c, *head, *p;
+ char *type = NULL;
+ int len, len2;
+
+#ifdef SEPOL_TARGET_XEN
+ if (policydbp->target_platform != SEPOL_TARGET_SELINUX) {
+ yyerror("genfs not supported for target");
+ return -1;
+ }
+#endif
+
+ if (pass == 1) {
+ free(fstype);
+ free(queue_remove(id_queue));
+ if (has_type)
+ free(queue_remove(id_queue));
+ parse_security_context(NULL);
+ return 0;
+ }
+
+ for (genfs_p = NULL, genfs = policydbp->genfs; genfs; genfs_p = genfs, genfs = genfs->next) {
+ if (strcmp(fstype, genfs->fstype) <= 0)
+ break;
+ }
+
+ if (!genfs || strcmp(fstype, genfs->fstype)) {
+ newgenfs = malloc(sizeof(struct genfs));
+ if (!newgenfs) {
+ yyerror("out of memory");
+ return -1;
+ }
+ memset(newgenfs, 0, sizeof(struct genfs));
+ newgenfs->fstype = fstype;
+ newgenfs->next = genfs;
+ if (genfs_p)
+ genfs_p->next = newgenfs;
+ else
+ policydbp->genfs = newgenfs;
+ genfs = newgenfs;
+ } else {
+ free(fstype);
+ fstype=NULL;
+ }
+
+ newc = (ocontext_t *) malloc(sizeof(ocontext_t));
+ if (!newc) {
+ yyerror("out of memory");
+ return -1;
+ }
+ memset(newc, 0, sizeof(ocontext_t));
+
+ newc->u.name = (char *)queue_remove(id_queue);
+ if (!newc->u.name)
+ goto fail;
+ if (has_type) {
+ type = (char *)queue_remove(id_queue);
+ if (!type)
+ goto fail;
+ if (type[1] != 0) {
+ yyerror2("invalid type %s", type);
+ goto fail;
+ }
+ switch (type[0]) {
+ case 'b':
+ newc->v.sclass = SECCLASS_BLK_FILE;
+ break;
+ case 'c':
+ newc->v.sclass = SECCLASS_CHR_FILE;
+ break;
+ case 'd':
+ newc->v.sclass = SECCLASS_DIR;
+ break;
+ case 'p':
+ newc->v.sclass = SECCLASS_FIFO_FILE;
+ break;
+ case 'l':
+ newc->v.sclass = SECCLASS_LNK_FILE;
+ break;
+ case 's':
+ newc->v.sclass = SECCLASS_SOCK_FILE;
+ break;
+ case '-':
+ newc->v.sclass = SECCLASS_FILE;
+ break;
+ default:
+ yyerror2("invalid type %s", type);
+ goto fail;
+ }
+ }
+ free(type);
+ type = NULL;
+ if (parse_security_context(&newc->context[0]))
+ goto fail;
+
+ head = genfs->head;
+
+ for (p = NULL, c = head; c; p = c, c = c->next) {
+ if (!strcmp(newc->u.name, c->u.name) && (!newc->v.sclass || !c->v.sclass || newc->v.sclass == c->v.sclass)) {
+ yyerror2("duplicate entry for genfs entry (%s, %s)", fstype, newc->u.name);
+ goto fail;
+ }
+ len = strlen(newc->u.name);
+ len2 = strlen(c->u.name);
+ if (len > len2)
+ break;
+ }
+
+ newc->next = c;
+ if (p)
+ p->next = newc;
+ else
+ genfs->head = newc;
+ return 0;
+ fail:
+ if (type)
+ free(type);
+ context_destroy(&newc->context[0]);
+ if (fstype)
+ free(fstype);
+ if (newc->u.name)
+ free(newc->u.name);
+ free(newc);
+ return -1;
+}
+
+int define_genfs_context(int has_type)
+{
+ return define_genfs_context_helper(queue_remove(id_queue), has_type);
+}
+
+int define_range_trans(int class_specified)
+{
+ char *id;
+ level_datum_t *levdatum = 0;
+ class_datum_t *cladatum;
+ range_trans_rule_t *rule;
+ int l, add = 1;
+
+ if (!mlspol) {
+ yyerror("range_transition rule in non-MLS configuration");
+ return -1;
+ }
+
+ if (pass == 1) {
+ while ((id = queue_remove(id_queue)))
+ free(id);
+ while ((id = queue_remove(id_queue)))
+ free(id);
+ if (class_specified)
+ while ((id = queue_remove(id_queue)))
+ free(id);
+ id = queue_remove(id_queue);
+ free(id);
+ for (l = 0; l < 2; l++) {
+ while ((id = queue_remove(id_queue))) {
+ free(id);
+ }
+ id = queue_remove(id_queue);
+ if (!id)
+ break;
+ free(id);
+ }
+ return 0;
+ }
+
+ rule = malloc(sizeof(struct range_trans_rule));
+ if (!rule) {
+ yyerror("out of memory");
+ return -1;
+ }
+ range_trans_rule_init(rule);
+
+ while ((id = queue_remove(id_queue))) {
+ if (set_types(&rule->stypes, id, &add, 0))
+ goto out;
+ }
+ add = 1;
+ while ((id = queue_remove(id_queue))) {
+ if (set_types(&rule->ttypes, id, &add, 0))
+ goto out;
+ }
+
+ if (class_specified) {
+ while ((id = queue_remove(id_queue))) {
+ if (!is_id_in_scope(SYM_CLASSES, id)) {
+ yyerror2("class %s is not within scope", id);
+ free(id);
+ goto out;
+ }
+ cladatum = hashtab_search(policydbp->p_classes.table, id);
+ if (!cladatum) {
+ yyerror2("unknown class %s", id);
+ goto out;
+ }
+
+ ebitmap_set_bit(&rule->tclasses, cladatum->s.value - 1, TRUE);
+ free(id);
+ }
+ } else {
+ cladatum = hashtab_search(policydbp->p_classes.table, "process");
+ if (!cladatum) {
+ yyerror2("could not find process class for " "legacy range_transition statement");
+ goto out;
+ }
+
+ ebitmap_set_bit(&rule->tclasses, cladatum->s.value - 1, TRUE);
+ }
+
+ id = (char *)queue_remove(id_queue);
+ if (!id) {
+ yyerror("no range in range_transition definition?");
+ goto out;
+ }
+ for (l = 0; l < 2; l++) {
+ levdatum = hashtab_search(policydbp->p_levels.table, id);
+ if (!levdatum) {
+ yyerror2("unknown level %s used in range_transition " "definition", id);
+ free(id);
+ goto out;
+ }
+ free(id);
+
+ rule->trange.level[l].sens = levdatum->level->sens;
+
+ while ((id = queue_remove(id_queue))) {
+ if (parse_semantic_categories(id, levdatum, &rule->trange.level[l].cat)) {
+ free(id);
+ goto out;
+ }
+ free(id);
+ }
+
+ id = (char *)queue_remove(id_queue);
+ if (!id)
+ break;
+ }
+ if (l == 0) {
+ if (mls_semantic_level_cpy(&rule->trange.level[1], &rule->trange.level[0])) {
+ yyerror("out of memory");
+ goto out;
+ }
+ }
+
+ append_range_trans(rule);
+ return 0;
+
+ out:
+ range_trans_rule_destroy(rule);
+ return -1;
+}
+
+/* FLASK */
diff --git a/libqpol/src/policy_define.h b/libqpol/src/policy_define.h
new file mode 100644
index 0000000..7be626c
--- /dev/null
+++ b/libqpol/src/policy_define.h
@@ -0,0 +1,75 @@
+/**
+ * @file policy_define.h
+ * This file is based upon checkpolicy/policy_define.h from NSA's SVN
+ * repository.
+ */
+
+/* Functions used to define policy grammar components. */
+
+#ifndef _POLICY_DEFINE_H_
+#define _POLICY_DEFINE_H_
+
+/*
+ * We need the following so we have a valid error return code in yacc
+ * when we have a parse error for a conditional rule. We can't check
+ * for NULL (ie 0) because that is a potentially valid return.
+ */
+#define COND_ERR ((avrule_t *)-1)
+
+#define TRUE 1
+#define FALSE 0
+
+/** parser used to support fs_use_psid declarations, so revert that bit
+ * of code here */
+#define SECURITY_FS_USE_PSIDS 6
+
+avrule_t *define_cond_compute_type(int which);
+avrule_t *define_cond_pol_list(avrule_t * avlist, avrule_t * stmt);
+avrule_t *define_cond_te_avtab(int which);
+cond_expr_t *define_cond_expr(uint32_t expr_type, void *arg1, void *arg2);
+int define_attrib(void);
+int define_av_perms(int inherits);
+int define_bool(void);
+int define_category(void);
+int define_class(void);
+int define_common_perms(void);
+int define_compute_type(int which);
+int define_conditional(cond_expr_t * expr, avrule_t * t_list, avrule_t * f_list);
+int define_constraint(constraint_expr_t * expr);
+int define_dominance(void);
+int define_fs_context(unsigned int major, unsigned int minor);
+int define_fs_use(int behavior);
+int define_genfs_context(int has_type);
+int define_initial_sid_context(void);
+int define_initial_sid(void);
+int define_ipv4_node_context(void);
+int define_ipv6_node_context(void);
+int define_level(void);
+int define_mls(void);
+int define_netif_context(void);
+int define_permissive(void);
+int define_polcap(void);
+int define_port_context(unsigned int low, unsigned int high);
+int define_pirq_context(unsigned int pirq);
+int define_iomem_context(unsigned long low, unsigned long high);
+int define_ioport_context(unsigned long low, unsigned long high);
+int define_pcidevice_context(unsigned long device);
+int define_range_trans(int class_specified);
+int define_role_allow(void);
+int define_role_trans(void);
+int define_role_types(void);
+int define_sens(void);
+int define_te_avtab(int which);
+int define_typealias(void);
+int define_typeattribute(void);
+int define_typebounds(void);
+int define_type(int alias);
+int define_user(void);
+int define_validatetrans(constraint_expr_t * expr);
+int insert_id(char *id, int push);
+int insert_separator(int push);
+role_datum_t *define_role_dom(role_datum_t * r);
+role_datum_t *merge_roles_dom(role_datum_t * r1, role_datum_t * r2);
+uintptr_t define_cexpr(uint32_t expr_type, uintptr_t arg1, uintptr_t arg2);
+
+#endif /* _POLICY_DEFINE_H_ */
diff --git a/libqpol/src/policy_extend.c b/libqpol/src/policy_extend.c
new file mode 100644
index 0000000..5325a87
--- /dev/null
+++ b/libqpol/src/policy_extend.c
@@ -0,0 +1,1397 @@
+/**
+ * @file
+ * Implementation of the interface for loading and using an extended
+ * policy image.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author Jeremy Solt jsolt@tresys.com
+ *
+ * Copyright (C) 2006-2008 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
+ */
+
+#include <config.h>
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/conditional.h>
+#include <sepol/policydb/avtab.h>
+#include <sepol/policydb/hashtab.h>
+#include <sepol/policydb/flask.h>
+#include <sepol/policydb/ebitmap.h>
+#include <sepol/policydb/expand.h>
+#ifdef HAVE_SEPOL_ERRCODES
+#include <sepol/errcodes.h>
+#endif
+#include <qpol/policy.h>
+#include <qpol/policy_extend.h>
+#include <qpol/iterator.h>
+#include <selinux/selinux.h>
+#include <errno.h>
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "qpol_internal.h"
+#include "iterator_internal.h"
+#include "syn_rule_internal.h"
+
+#ifdef SETOOLS_DEBUG
+#include <math.h>
+#endif
+
+#define OBJECT_R "object_r"
+
+#define QPOL_SYN_RULE_TABLE_BITS 16
+#define QPOL_SYN_RULE_TABLE_SIZE (1 << QPOL_SYN_RULE_TABLE_BITS)
+#define QPOL_SYN_RULE_TABLE_MASK (QPOL_SYN_RULE_TABLE_SIZE - 1)
+
+/* original hashing function below */
+/*
+#define QPOL_SYN_RULE_TABLE_HASH(rule_key) \
+((rule_key->class_val + \
+ (rule_key->target_val << 2) +\
+ (rule_key->source_val << 9)) & \
+ QPOL_SYN_RULE_TABLE_MASK)
+*/
+
+/* new hashing function, introduced in SETools 3.3 */
+#define QPOL_SYN_RULE_TABLE_HASH(rule_key) \
+(((((rule_key->source_val & 0xff) << 8) | (rule_key->target_val & 0xff)) ^ \
+ (rule_key->class_val & 0xf) ^ \
+ ((int) ((size_t) rule_key->cond) & 0xfff0)) & QPOL_SYN_RULE_TABLE_MASK)
+
+typedef struct qpol_syn_rule_key
+{
+ uint32_t rule_type;
+ uint32_t source_val;
+ uint32_t target_val;
+ uint32_t class_val;
+ cond_node_t *cond;
+} qpol_syn_rule_key_t;
+
+typedef struct qpol_syn_rule_list
+{
+ struct qpol_syn_rule *rule;
+ struct qpol_syn_rule_list *next;
+} qpol_syn_rule_list_t;
+
+typedef struct qpol_syn_rule_node
+{
+ qpol_syn_rule_key_t key;
+ qpol_syn_rule_list_t *rules;
+ struct qpol_syn_rule_node *next;
+} qpol_syn_rule_node_t;
+
+typedef struct qpol_syn_rule_table
+{
+ qpol_syn_rule_node_t **buckets;
+} qpol_syn_rule_table_t;
+
+typedef struct qpol_extended_image
+{
+ qpol_syn_rule_table_t *syn_rule_table;
+ struct qpol_syn_rule **syn_rule_master_list;
+ size_t master_list_sz;
+} qpol_extended_image_t;
+
+struct extend_bogus_alias_struct
+{
+ qpol_policy_t *q;
+ int num_bogus_aliases;
+};
+
+static int extend_find_bogus_alias(hashtab_key_t key __attribute__ ((unused)), hashtab_datum_t datum, void *args)
+{
+ struct extend_bogus_alias_struct *e = (struct extend_bogus_alias_struct *)args;
+ /* within libqpol, qpol_type_t is the same a libsepol's type_datum_t */
+ qpol_type_t *qtype = (qpol_type_t *) datum;
+ type_datum_t *type = (type_datum_t *) datum;
+ unsigned char isalias;
+ qpol_type_get_isalias(e->q, qtype, &isalias);
+ return isalias && type->s.value == 0;
+}
+
+static void extend_remove_bogus_alias(hashtab_key_t key, hashtab_datum_t datum, void *args)
+{
+ struct extend_bogus_alias_struct *e = (struct extend_bogus_alias_struct *)args;
+ free(key);
+ type_datum_t *type = (type_datum_t *) datum;
+ type_datum_destroy(type);
+ free(type);
+ e->num_bogus_aliases++;
+}
+
+/**
+ * Search the policy for aliases that have a value of 0. These come
+ * from modular policies with disabled aliases, but end up being
+ * written to the policy anyways due to a bug in libsepol. These
+ * bogus aliases are removed from the policy.
+ * @param policy Policy that may contain broken aliases. This policy
+ * will be altered by this function.
+ * @return 0 on success and < 0 on failure; if the call fails, errno
+ * will be set. On failure, the policy state may be inconsistent.
+ */
+static int qpol_policy_remove_bogus_aliases(qpol_policy_t * policy)
+{
+ policydb_t *db = NULL;
+
+ if (policy == NULL) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+ struct extend_bogus_alias_struct e = { policy, 0 };
+ hashtab_map_remove_on_error(db->p_types.table, extend_find_bogus_alias, extend_remove_bogus_alias, &e);
+
+#ifdef SETOOLS_DEBUG
+ if (e.num_bogus_aliases > 0) {
+ WARN(policy, "%s", "This policy contained disabled aliases; they have been removed.");
+ }
+#endif
+
+ return 0;
+}
+
+/**
+ * Builds data for the attributes and inserts them into the policydb.
+ * This function modifies the policydb. Names created for attributes
+ * are of the form @ttr<value> where value is the value of the attribute
+ * as a four digit number (prepended with 0's as needed).
+ * @param policy The policy from which to read the attribute map and
+ * create the type data for the attributes. This policy will be altered
+ * by this function.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set. On failure, the policy state may be inconsistent
+ * especially in the case where the hashtab functions return the error.
+ */
+static int qpol_policy_build_attrs_from_map(qpol_policy_t * policy)
+{
+ policydb_t *db = NULL;
+ size_t i;
+ uint32_t bit = 0, count = 0;
+ ebitmap_node_t *node = NULL;
+ type_datum_t *tmp_type = NULL, *orig_type;
+ char *tmp_name = NULL, buff[10];
+ int error = 0, retv;
+
+ INFO(policy, "%s", "Generating attributes for policy. (Step 4 of 5)");
+ if (policy == NULL) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return -1;
+ }
+
+ db = &policy->p->p;
+
+ memset(&buff, 0, 10 * sizeof(char));
+
+ for (i = 0; i < db->p_types.nprim; i++) {
+ count = 0;
+ ebitmap_for_each_bit(&db->attr_type_map[i], node, bit) {
+ if (ebitmap_node_get_bit(node, bit))
+ count++;
+ }
+ if (count == 0) {
+ continue;
+ }
+ /* first create a new type_datum_t for the attribute,
+ * with the attribute's type_list consisting of types
+ * with this attribute */
+ /* Does not exist */
+ if (db->p_type_val_to_name[i] == NULL){
+ snprintf(buff, 9, "@ttr%04zd", i + 1);
+ tmp_name = strdup(buff);
+ if (!tmp_name) {
+ error = errno;
+ goto err;
+ }
+ }
+
+ /* Already exists */
+ else
+ tmp_name = db->p_type_val_to_name[i];
+
+ tmp_type = calloc(1, sizeof(type_datum_t));
+ if (!tmp_type) {
+ error = errno;
+ goto err;
+ }
+ tmp_type->primary = 1;
+ tmp_type->flavor = TYPE_ATTRIB;
+ tmp_type->s.value = i + 1;
+ if (ebitmap_cpy(&tmp_type->types, &db->attr_type_map[i])) {
+ error = ENOMEM;
+ goto err;
+ }
+
+ /* now go through each of the member types, and set
+ * their type_list bit to point back */
+ ebitmap_for_each_bit(&tmp_type->types, node, bit) {
+ if (ebitmap_node_get_bit(node, bit)) {
+ orig_type = db->type_val_to_struct[bit];
+ if (ebitmap_set_bit(&orig_type->types, tmp_type->s.value - 1, 1)) {
+ error = ENOMEM;
+ goto err;
+ }
+ }
+ }
+ /* Does not exist - insert new */
+ if (db->p_type_val_to_name[i] == NULL){
+ retv = hashtab_insert(db->p_types.table, (hashtab_key_t) tmp_name, (hashtab_datum_t) tmp_type);
+ if (retv) {
+ if (retv == SEPOL_ENOMEM)
+ error = db->p_types.table ? ENOMEM : EINVAL;
+ else
+ error = EEXIST;
+ goto err;
+ }
+ }
+ /* Already exists - replace old */
+ else {
+ retv = hashtab_replace(db->p_types.table, (hashtab_key_t) tmp_name, (hashtab_datum_t) tmp_type, NULL, NULL);
+ if (retv) {
+ if (retv == SEPOL_ENOMEM)
+ error = db->p_types.table ? ENOMEM : EINVAL;
+ else
+ error = EEXIST;
+ goto err;
+ }
+ }
+
+ db->p_type_val_to_name[i] = tmp_name;
+ db->type_val_to_struct[i] = tmp_type;
+
+ /* memory now owned by symtab do not free */
+ tmp_name = NULL;
+ tmp_type = NULL;
+ }
+
+ return STATUS_SUCCESS;
+
+ err:
+ free(tmp_name);
+ type_datum_destroy(tmp_type);
+ free(tmp_type);
+ ERR(policy, "%s", strerror(error));
+ errno = error;
+ return STATUS_ERR;
+}
+
+/**
+ * Builds data for empty attributes and inserts them into the policydb.
+ * This function modifies the policydb. Names created for the attributes
+ * are of the form @ttr<value> where value is the value of the attribute
+ * as a four digit number (prepended with 0's as needed).
+ * @param policy The policy to which to add type data for attributes.
+ * This policy will be altered by this function.
+ * @return Returns 0 on success and < 0 on failure; if the call fails,
+ * errno will be set. On failure, the policy state may be inconsistent
+ * especially in the case where the hashtab functions return the error.
+ */
+static int qpol_policy_fill_attr_holes(qpol_policy_t * policy)
+{
+ policydb_t *db = NULL;
+ char *tmp_name = NULL, buff[10];
+ int error = 0, retv = 0;
+ ebitmap_t tmp_bmap = { NULL, 0 };
+ type_datum_t *tmp_type = NULL;
+ size_t i;
+
+ if (policy == NULL) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+
+ memset(&buff, 0, 10 * sizeof(char));
+
+ for (i = 0; i < db->p_types.nprim; i++) {
+ if (db->type_val_to_struct[i])
+ continue;
+ snprintf(buff, 9, "@ttr%04zd", i + 1);
+ tmp_name = strdup(buff);
+ if (!tmp_name) {
+ error = errno;
+ goto err;
+ }
+ tmp_type = calloc(1, sizeof(type_datum_t));
+ if (!tmp_type) {
+ error = errno;
+ goto err;
+ }
+ tmp_type->primary = 1;
+ tmp_type->flavor = TYPE_ATTRIB;
+ tmp_type->s.value = i + 1;
+ tmp_type->types = tmp_bmap;
+
+ retv = hashtab_insert(db->p_types.table, (hashtab_key_t) tmp_name, (hashtab_datum_t) tmp_type);
+ if (retv) {
+ if (retv == SEPOL_ENOMEM)
+ error = db->p_types.table ? ENOMEM : EINVAL;
+ else
+ error = EEXIST;
+ goto err;
+ }
+ db->p_type_val_to_name[i] = tmp_name;
+ db->type_val_to_struct[i] = tmp_type;
+
+ /* memory now owned by symtab do not free */
+ tmp_name = NULL;
+ tmp_type = NULL;
+ }
+
+ return STATUS_SUCCESS;
+
+ err:
+ free(tmp_type);
+ free(tmp_name);
+ ERR(policy, "%s", strerror(error));
+ errno = error;
+ return STATUS_ERR;
+}
+
+static char *sidnames[] = {
+ "undefined",
+ "kernel",
+ "security",
+ "unlabeled",
+ "fs",
+ "file",
+ "file_labels",
+ "init",
+ "any_socket",
+ "port",
+ "netif",
+ "netmsg",
+ "node",
+ "igmp_packet",
+ "icmp_socket",
+ "tcp_socket",
+ "sysctl_modprobe",
+ "sysctl",
+ "sysctl_fs",
+ "sysctl_kernel",
+ "sysctl_net",
+ "sysctl_net_unix",
+ "sysctl_vm",
+ "sysctl_dev",
+ "kmod",
+ "policy",
+ "scmp_packet",
+ "devnull"
+};
+
+/**
+ * Uses names from flask to fill in the isid names which are not normally
+ * saved. This function modified the policydb.
+ * @param policy Policy to which to add sid names.
+ * This policy will be altered by this function.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set. On failure, the policy state may be inconsistent.
+ */
+static int qpol_policy_add_isid_names(qpol_policy_t * policy)
+{
+ policydb_t *db = NULL;
+ ocontext_t *sid = NULL;
+ uint32_t val = 0;
+ int error = 0;
+
+ if (policy == NULL) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+
+ for (sid = db->ocontexts[OCON_ISID]; sid; sid = sid->next) {
+ val = (uint32_t) sid->sid[0];
+ if (val > SECINITSID_NUM)
+ val = 0;
+
+ if (!sid->u.name) {
+ sid->u.name = strdup(sidnames[val]);
+ if (!sid->u.name) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ errno = error;
+ return STATUS_ERR;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int extend_assign_role_to_user(hashtab_key_t k __attribute__ ((unused)), hashtab_datum_t d, void *args)
+{
+ user_datum_t *user = (user_datum_t *) d;
+ uint32_t *value = (uint32_t *) args;
+ if (ebitmap_set_bit(&user->roles.roles, *value - 1, 1)) {
+ return -1;
+ }
+ return 0;
+}
+
+/**
+ * Modify the special role 'object_r' by assigning it to all users,
+ * and all types to object_r. This function modifies the policydb.
+ * @param policy Policy containing object_r. This policy will be
+ * altered by this function.
+ * @return 0 on success and < 0 on failure; if the call fails, errno
+ * will be set. On failure, the policy state may be inconsistent.
+ */
+static int qpol_policy_add_object_r(qpol_policy_t * policy)
+{
+ policydb_t *db = NULL;
+ int error = 0;
+
+ if (policy == NULL) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+
+ hashtab_datum_t datum = hashtab_search(db->p_roles.table, (const hashtab_key_t)OBJECT_R);
+ if (datum == NULL) {
+ ERR(policy, "%s", OBJECT_R " not found in policy!");
+ errno = EIO;
+ assert(0);
+ return STATUS_ERR;
+ }
+
+ role_datum_t *role = (role_datum_t *) datum;
+
+ uint32_t value = role->s.value;
+
+ if (hashtab_map(db->p_users.table, extend_assign_role_to_user, &value) < 0) {
+ return STATUS_ERR;
+ }
+
+ qpol_iterator_t *iter;
+ if (qpol_policy_get_type_iter(policy, &iter) < 0) {
+ return STATUS_ERR;
+ }
+ for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
+ const qpol_type_t *type;
+ unsigned char isattr, isalias;
+ if (qpol_iterator_get_item(iter, (void **)&type) < 0 ||
+ qpol_type_get_isattr(policy, type, &isattr) < 0 || qpol_type_get_isalias(policy, type, &isalias) < 0) {
+ error = errno;
+ qpol_iterator_destroy(&iter);
+ errno = error;
+ return STATUS_ERR;
+ }
+ if (isattr || isalias) {
+ continue;
+ }
+ if (qpol_type_get_value(policy, type, &value) < 0) {
+ error = errno;
+ qpol_iterator_destroy(&iter);
+ errno = error;
+ return STATUS_ERR;
+ }
+ if (ebitmap_set_bit(&role->types.types, value - 1, 1)) {
+ error = errno;
+ qpol_iterator_destroy(&iter);
+ errno = error;
+ return STATUS_ERR;
+ }
+ }
+ qpol_iterator_destroy(&iter);
+
+ return 0;
+}
+
+/**
+ * If the given policy's version is higher than the running system's
+ * version, then mark it as different. In a future version of
+ * libqpol, accessors will return data as if the policy were really
+ * the new version rather than what it actually is.
+ */
+static int qpol_policy_match_system(qpol_policy_t * policy)
+{
+ int kernvers = security_policyvers();
+ int currentvers = policy->p->p.policyvers;
+ int error;
+ if (kernvers < 0) {
+ error = errno;
+ ERR(policy, "%s", "Could not determine running system's policy version.");
+ errno = error;
+ return -1;
+ }
+ if (policy->p->p.policyvers > kernvers) {
+ if (sepol_policydb_set_vers(policy->p, kernvers)) {
+ error = errno;
+ ERR(policy, "Could not downgrade policy to version %d.", kernvers);
+ errno = error;
+ return -1;
+ }
+ WARN(policy, "Policy would be downgraded from version %d to %d.", currentvers, kernvers);
+ }
+ return 0;
+}
+
+/**
+ * Walks the conditional list and adds links for reverse look up from
+ * a te/av rule to the conditional from which it came.
+ * @param policy The policy to which to add conditional trace backs.
+ * This policy will be altered by this function.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set. On failure, the policy state may be inconsistent.
+ */
+static int qpol_policy_add_cond_rule_traceback(qpol_policy_t * policy)
+{
+ policydb_t *db = NULL;
+ cond_node_t *cond = NULL;
+ cond_av_list_t *list_ptr = NULL;
+ qpol_iterator_t *iter = NULL;
+ avtab_ptr_t rule = NULL;
+ int error = 0;
+ uint32_t rules = 0;
+
+ INFO(policy, "%s", "Building conditional rules tables. (Step 5 of 5)");
+ if (!policy) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+
+ rules = (QPOL_RULE_ALLOW | QPOL_RULE_AUDITALLOW | QPOL_RULE_DONTAUDIT);
+ if (!(policy->options & QPOL_POLICY_OPTION_NO_NEVERALLOWS))
+ rules |= QPOL_RULE_NEVERALLOW;
+
+ /* mark all unconditional rules as enabled */
+ if (qpol_policy_get_avrule_iter(policy, rules, &iter))
+ return STATUS_ERR;
+ for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
+ if (qpol_iterator_get_item(iter, (void **)&rule)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ errno = error;
+ return STATUS_ERR;
+ }
+ rule->parse_context = NULL;
+ rule->merged = QPOL_COND_RULE_ENABLED;
+ }
+ qpol_iterator_destroy(&iter);
+ if (qpol_policy_get_terule_iter(policy, (QPOL_RULE_TYPE_TRANS | QPOL_RULE_TYPE_CHANGE | QPOL_RULE_TYPE_MEMBER), &iter))
+ return STATUS_ERR;
+ for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
+ if (qpol_iterator_get_item(iter, (void **)&rule)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ errno = error;
+ return STATUS_ERR;
+ }
+ rule->parse_context = NULL;
+ rule->merged = QPOL_COND_RULE_ENABLED;
+ }
+ qpol_iterator_destroy(&iter);
+
+ for (cond = db->cond_list; cond; cond = cond->next) {
+ /* evaluate cond */
+ cond->cur_state = cond_evaluate_expr(db, cond->expr);
+ if (cond->cur_state < 0) {
+ ERR(policy, "Error evaluating conditional: %s", strerror(EILSEQ));
+ errno = EILSEQ;
+ return STATUS_ERR;
+ }
+
+ /* walk true list */
+ for (list_ptr = cond->true_list; list_ptr; list_ptr = list_ptr->next) {
+ /* field not used after parse, now stores cond */
+ list_ptr->node->parse_context = (void *)cond;
+ /* field not used (except by write),
+ * now storing list and enabled flags */
+ list_ptr->node->merged = QPOL_COND_RULE_LIST;
+ if (cond->cur_state)
+ list_ptr->node->merged |= QPOL_COND_RULE_ENABLED;
+ }
+
+ /* walk false list */
+ for (list_ptr = cond->false_list; list_ptr; list_ptr = list_ptr->next) {
+ /* field not used after parse, now stores cond */
+ list_ptr->node->parse_context = (void *)cond;
+ /* field not used (except by write),
+ * now storing list and enabled flags */
+ list_ptr->node->merged = 0; /* i.e. !QPOL_COND_RULE_LIST */
+ if (!cond->cur_state)
+ list_ptr->node->merged |= QPOL_COND_RULE_ENABLED;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Free all allocated memory used by a qpol_syn_rule.
+ * @param r Reference pointer to the rule to destroy.
+ */
+static void qpol_syn_rule_destroy(struct qpol_syn_rule **r)
+{
+ if (!r || !(*r))
+ return;
+
+ free(*r);
+ *r = NULL;
+}
+
+/**
+ * Free all memory used by a syn rule list.
+ * @param list Reference pointer to the head node of
+ * the syn rule list to destroy. All nodes in the list will
+ * be destroyed.
+ */
+static void qpol_syn_rule_list_destroy(qpol_syn_rule_list_t ** list)
+{
+ qpol_syn_rule_list_t *cur = NULL, *next = NULL;
+
+ if (!list || !(*list))
+ return;
+
+ for (cur = *list; cur; cur = next) {
+ next = cur->next;
+ free(cur);
+ }
+}
+
+/**
+ * Free all memory used by a syn rule node in the rule table.
+ * @param node Reference pointer to the first node in the chain.
+ * All nodes in the chain will be destroyed.
+ */
+static void qpol_syn_rule_node_destroy(qpol_syn_rule_node_t ** node)
+{
+ qpol_syn_rule_node_t *cur = NULL, *next = NULL;
+
+ if (!node || !(*node))
+ return;
+
+ for (cur = *node; cur; cur = next) {
+ next = cur->next;
+ qpol_syn_rule_list_destroy(&cur->rules);
+ free(cur);
+ }
+}
+
+/**
+ * Free all memory used by the syntactic rule table.
+ * @param t Reference pointer to the table to destroy.
+ */
+static void qpol_syn_rule_table_destroy(qpol_syn_rule_table_t ** t)
+{
+ size_t i = 0;
+
+ if (!t || !(*t))
+ return;
+
+ for (i = 0; i < QPOL_SYN_RULE_TABLE_SIZE; i++)
+ qpol_syn_rule_node_destroy(&((*t)->buckets[i]));
+
+ free((*t)->buckets);
+ free(*t);
+ *t = NULL;
+}
+
+/**
+ * Find the node in the syntactic rule hash table corresponding to a key.
+ * @param table The table to search.
+ * @param key The key for which to search.
+ * @return a valid qpol_syn_rule_node_t pointer on success or NULL on failure.
+ */
+static qpol_syn_rule_node_t *qpol_syn_rule_table_find_node_by_key(const qpol_syn_rule_table_t * table,
+ const qpol_syn_rule_key_t * key)
+{
+ qpol_syn_rule_node_t *node = NULL;
+
+ for (node = table->buckets[QPOL_SYN_RULE_TABLE_HASH(key)]; node; node = node->next) {
+ if ((node->key.rule_type & key->rule_type) &&
+ (node->key.source_val == key->source_val) &&
+ (node->key.target_val == key->target_val) &&
+ (node->key.class_val == key->class_val) && (node->key.cond == key->cond))
+ return node;
+ }
+
+ return NULL;
+}
+
+/**
+ * Given a syn rule key and a syn rule, adds the key/rule pair to the
+ * syn rule table. Note that this function takes ownership of the
+ * key.
+ *
+ * @param policy Policy associated with the rule.
+ * @param table The table to which to add the rule.
+ * @param key Hashtable key for rule lookup.
+ * @param rule The rule to add.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and the table may be in an inconsistent state.
+ */
+static int qpol_syn_rule_table_insert_entry(qpol_policy_t * policy,
+ qpol_syn_rule_table_t * table, qpol_syn_rule_key_t * key, struct qpol_syn_rule *rule)
+{
+ int error = 0;
+ qpol_syn_rule_node_t *table_node = NULL;
+ qpol_syn_rule_list_t *list_entry = NULL;
+
+ if (!(list_entry = malloc(sizeof(qpol_syn_rule_list_t)))) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ return -1;
+ }
+ list_entry->rule = rule;
+
+ table_node = qpol_syn_rule_table_find_node_by_key(table, key);
+ if (table_node) {
+ list_entry->next = table_node->rules;
+ table_node->rules = list_entry;
+ } else {
+ list_entry->next = NULL;
+ if (!(table_node = malloc(sizeof(qpol_syn_rule_node_t)))) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ free(list_entry);
+ return -1;
+ }
+ table_node->key = *key;
+ table_node->rules = list_entry;
+ size_t hash = QPOL_SYN_RULE_TABLE_HASH(key);
+ table_node->next = table->buckets[hash];
+ table->buckets[hash] = table_node;
+ }
+ return 0;
+}
+
+/**
+ * Add a syntactic rule (sepol's avrule_t) to the syntactic rule table.
+ * @param policy Policy associated with the rule.
+ * @param table The table to which to add the rule.
+ * @param rule The rule to add.
+ * @param cond The conditional associated with the rule (NULL if
+ * unconditional). with the rule (needed for conditional tracking).
+ * @param branch If the rule is conditional, then 0 if in the true
+ * branch, 1 if in else.
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set and the table may be in an inconsistent state.
+ */
+static int qpol_syn_rule_table_insert_sepol_avrule(qpol_policy_t * policy, qpol_syn_rule_table_t * table, avrule_t * rule,
+ cond_node_t * cond, int branch)
+{
+ int error = 0;
+ qpol_syn_rule_key_t key = { 0, 0, 0, 0, NULL };
+ struct qpol_syn_rule *new_rule = NULL;
+ ebitmap_t source_types, source_types2, target_types, target_types2;
+ ebitmap_node_t *snode = NULL, *tnode = NULL;
+ unsigned int i, j;
+ class_perm_node_t *class_node = NULL;
+
+ if (!(new_rule = malloc(sizeof(struct qpol_syn_rule)))) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto err;
+ }
+ new_rule->rule = rule;
+ new_rule->cond = cond;
+ new_rule->cond_branch = branch;
+
+ policy->ext->syn_rule_master_list[policy->ext->master_list_sz] = new_rule;
+ policy->ext->master_list_sz++;
+
+ if (type_set_expand(&rule->stypes, &source_types, &policy->p->p, 0) ||
+ type_set_expand(&rule->stypes, &source_types2, &policy->p->p, 1)) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ error = ENOMEM;
+ goto err;
+ }
+ if (type_set_expand(&rule->ttypes, &target_types, &policy->p->p, 0) ||
+ type_set_expand(&rule->ttypes, &target_types2, &policy->p->p, 1)) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ error = ENOMEM;
+ goto err;
+ }
+ if (ebitmap_union(&source_types, &source_types2) || ebitmap_union(&target_types, &target_types2)) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ error = ENOMEM;
+ goto err;
+ }
+ ebitmap_for_each_bit(&source_types, snode, i) {
+ if (!ebitmap_get_bit(&source_types, i))
+ continue;
+ if (rule->flags & RULE_SELF) {
+ for (class_node = rule->perms; class_node; class_node = class_node->next) {
+ key.rule_type = rule->specified;
+ key.source_val = key.target_val = i + 1;
+ key.class_val = class_node->class;
+ key.cond = cond;
+ if (qpol_syn_rule_table_insert_entry(policy, table, &key, new_rule))
+ goto err;
+ }
+ }
+ ebitmap_for_each_bit(&target_types, tnode, j) {
+ if (!ebitmap_get_bit(&target_types, j))
+ continue;
+ for (class_node = rule->perms; class_node; class_node = class_node->next) {
+ key.rule_type = rule->specified;
+ key.source_val = i + 1;
+ key.target_val = j + 1;
+ key.class_val = class_node->class;
+ key.cond = cond;
+ if (qpol_syn_rule_table_insert_entry(policy, table, &key, new_rule))
+ goto err;
+ }
+ }
+ }
+
+ ebitmap_destroy(&source_types);
+ ebitmap_destroy(&source_types2);
+ ebitmap_destroy(&target_types);
+ ebitmap_destroy(&target_types2);
+ return 0;
+
+ err:
+ ebitmap_destroy(&source_types);
+ ebitmap_destroy(&source_types2);
+ ebitmap_destroy(&target_types);
+ ebitmap_destroy(&target_types2);
+ return -1;
+}
+
+int qpol_policy_build_syn_rule_table(qpol_policy_t * policy)
+{
+ int error = 0, created = 0;
+ avrule_block_t *cur_block = NULL;
+ avrule_decl_t *decl = NULL;
+ avrule_t *cur_rule = NULL;
+ cond_node_t *cur_cond = NULL, *remapped_cond;
+
+ if (!policy) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!policy->ext) {
+ policy->ext = calloc(1, sizeof(qpol_extended_image_t));
+ if (!policy->ext) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto err;
+ }
+ }
+
+ if (policy->ext->syn_rule_table)
+ return 0; /* already built */
+
+ policy->ext->syn_rule_table = calloc(1, sizeof(qpol_syn_rule_table_t));
+ if (!policy->ext->syn_rule_table) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto err;
+ }
+ policy->ext->syn_rule_table->buckets = calloc(QPOL_SYN_RULE_TABLE_SIZE, sizeof(qpol_syn_rule_node_t *));
+ if (!policy->ext->syn_rule_table->buckets) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto err;
+ }
+
+ policy->ext->master_list_sz = 0;
+ for (cur_block = policy->p->p.global; cur_block; cur_block = cur_block->next) {
+ decl = cur_block->enabled;
+ if (!decl)
+ continue;
+
+ for (cur_rule = decl->avrules; cur_rule; cur_rule = cur_rule->next) {
+ policy->ext->master_list_sz++;
+ }
+ for (cur_cond = decl->cond_list; cur_cond; cur_cond = cur_cond->next) {
+ for (cur_rule = cur_cond->avtrue_list; cur_rule; cur_rule = cur_rule->next) {
+ policy->ext->master_list_sz++;
+ }
+ for (cur_rule = cur_cond->avfalse_list; cur_rule; cur_rule = cur_rule->next) {
+ policy->ext->master_list_sz++;
+ }
+ }
+ }
+
+ if (policy->ext->master_list_sz == 0) {
+ policy->ext->syn_rule_master_list = NULL;
+ return 0; /* policy is not a source policy */
+ }
+
+ INFO(policy, "%s", "Building syntactic rules tables.");
+
+ policy->ext->syn_rule_master_list = calloc(policy->ext->master_list_sz, sizeof(struct qpol_syn_rule *));
+ if (!policy->ext->syn_rule_master_list) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto err;
+ }
+
+ /* reset size as it will represent the current number of elements inserted */
+ policy->ext->master_list_sz = 0;
+
+ for (cur_block = policy->p->p.global; cur_block; cur_block = cur_block->next) {
+ decl = cur_block->enabled;
+ if (!decl)
+ continue;
+
+ for (cur_rule = decl->avrules; cur_rule; cur_rule = cur_rule->next) {
+ if (qpol_syn_rule_table_insert_sepol_avrule(policy, policy->ext->syn_rule_table, cur_rule, NULL, 0)) {
+ error = errno;
+ goto err;
+ }
+ }
+ for (cur_cond = decl->cond_list; cur_cond; cur_cond = cur_cond->next) {
+ /* convert the cond within an avrule_decl to
+ * the expanded cond */
+ remapped_cond = cond_node_find(&policy->p->p, cur_cond, policy->p->p.cond_list, &created);
+ if (created || !remapped_cond) {
+ cond_node_destroy(remapped_cond);
+ error = EIO;
+ ERR(policy, "%s", "Inconsistent conditional records");
+ assert(0);
+ goto err;
+ }
+ for (cur_rule = cur_cond->avtrue_list; cur_rule; cur_rule = cur_rule->next) {
+ if (qpol_syn_rule_table_insert_sepol_avrule
+ (policy, policy->ext->syn_rule_table, cur_rule, remapped_cond, 0)) {
+ error = errno;
+ goto err;
+ }
+ }
+ for (cur_rule = cur_cond->avfalse_list; cur_rule; cur_rule = cur_rule->next) {
+ if (qpol_syn_rule_table_insert_sepol_avrule
+ (policy, policy->ext->syn_rule_table, cur_rule, remapped_cond, 1)) {
+ error = errno;
+ goto err;
+ }
+ }
+ }
+ }
+
+#ifdef SETOOLS_DEBUG
+ /*
+ * Debugging code to measure the how well the syntactic rules
+ * are being hashed. Calculate the min, max, and std
+ * deviation.
+ */
+ size_t bucket;
+ float o2 = 0.0f;
+ long total_entries = 0;
+ for (bucket = 0; bucket < QPOL_SYN_RULE_TABLE_SIZE; bucket++) {
+ qpol_syn_rule_node_t *n = policy->ext->syn_rule_table->buckets[bucket];
+ while (n != NULL) {
+ total_entries++;
+ n = n->next;
+ }
+ }
+ float expected_value = total_entries * 1.0f / QPOL_SYN_RULE_TABLE_SIZE;
+ size_t min_items = total_entries;
+ size_t max_items = 0;
+ for (bucket = 0; bucket < QPOL_SYN_RULE_TABLE_SIZE; bucket++) {
+ size_t num_items = 0;
+ qpol_syn_rule_node_t *n = policy->ext->syn_rule_table->buckets[bucket];
+ while (n != NULL) {
+ num_items++;
+ n = n->next;
+ }
+ if (num_items > max_items) {
+ max_items = num_items;
+ }
+ if (num_items < min_items) {
+ min_items = num_items;
+ }
+ o2 += (num_items - expected_value) * (num_items - expected_value);
+ }
+ float stddev = sqrtf(o2 / (QPOL_SYN_RULE_TABLE_SIZE - 1));
+ fprintf(stderr, "libqpol synrule table %d bits: total entries %lu, expected %g\n", QPOL_SYN_RULE_TABLE_BITS, total_entries,
+ expected_value);
+ fprintf(stderr, " min %zd, max %zd, stddev %g\n", min_items, max_items, stddev);
+#endif
+
+ return 0;
+
+ err:
+ if (policy->ext)
+ qpol_syn_rule_table_destroy(&policy->ext->syn_rule_table);
+ errno = error;
+ return -1;
+}
+
+/**
+ * Free all memory used by a qpol extended image and set it to NULL.
+ * @param ext The extended image to destroy.
+ */
+void qpol_extended_image_destroy(qpol_extended_image_t ** ext)
+{
+ size_t i = 0;
+
+ if (!ext || !(*ext))
+ return;
+
+ qpol_syn_rule_table_destroy(&((*ext)->syn_rule_table));
+
+ for (i = 0; i < (*ext)->master_list_sz; i++) {
+ qpol_syn_rule_destroy(&((*ext)->syn_rule_master_list[i]));
+ }
+ free((*ext)->syn_rule_master_list);
+
+ free(*ext);
+ *ext = NULL;
+}
+
+int policy_extend(qpol_policy_t * policy)
+{
+ int retv, error;
+ policydb_t *db = NULL;
+
+ if (policy == NULL) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return -1;
+ }
+
+ db = &policy->p->p;
+
+ retv = qpol_policy_remove_bogus_aliases(policy);
+ if (retv) {
+ error = errno;
+ goto err;
+ }
+ if (db->attr_type_map) {
+ retv = qpol_policy_build_attrs_from_map(policy);
+ if (retv) {
+ error = errno;
+ goto err;
+ }
+ if (db->policy_type == POLICY_KERN) {
+ retv = qpol_policy_fill_attr_holes(policy);
+ if (retv) {
+ error = errno;
+ goto err;
+ }
+ }
+ }
+ retv = qpol_policy_add_isid_names(policy);
+ if (retv) {
+ error = errno;
+ goto err;
+ }
+ retv = qpol_policy_add_object_r(policy);
+ if (retv) {
+ error = errno;
+ goto err;
+ }
+
+ if ((policy->options & QPOL_POLICY_OPTION_MATCH_SYSTEM) && qpol_policy_match_system(policy)) {
+ error = errno;
+ goto err;
+ }
+
+ if (policy->options & QPOL_POLICY_OPTION_NO_RULES)
+ return STATUS_SUCCESS;
+
+ retv = qpol_policy_add_cond_rule_traceback(policy);
+ if (retv) {
+ error = errno;
+ goto err;
+ }
+
+ return STATUS_SUCCESS;
+
+ err:
+ /* no need to call ERR here as it will already have been called */
+ qpol_extended_image_destroy(&policy->ext);
+ errno = error;
+ return STATUS_ERR;
+}
+
+typedef struct syn_rule_state
+{
+ qpol_syn_rule_node_t *node;
+ qpol_syn_rule_list_t *cur;
+} syn_rule_state_t;
+
+static int syn_rule_state_end(const qpol_iterator_t * iter)
+{
+ syn_rule_state_t *srs = NULL;
+
+ if (!iter || !(srs = qpol_iterator_state(iter))) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ return (srs->cur ? 0 : 1);
+}
+
+static void *syn_rule_state_get_cur(const qpol_iterator_t * iter)
+{
+ syn_rule_state_t *srs = NULL;
+
+ if (!iter || !(srs = qpol_iterator_state(iter)) || qpol_iterator_end(iter)) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ return srs->cur->rule;
+}
+
+static int syn_rule_state_next(qpol_iterator_t * iter)
+{
+ syn_rule_state_t *srs = NULL;
+
+ if (!iter || !(srs = qpol_iterator_state(iter))) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+ if (qpol_iterator_end(iter)) {
+ errno = ERANGE;
+ return STATUS_ERR;
+ }
+
+ srs->cur = srs->cur->next;
+
+ return STATUS_SUCCESS;
+}
+
+static size_t syn_rule_state_size(const qpol_iterator_t * iter)
+{
+ size_t count = 0;
+ qpol_syn_rule_list_t *tmp = NULL;
+ syn_rule_state_t *srs = NULL;
+
+ if (!iter || !(srs = qpol_iterator_state(iter))) {
+ errno = EINVAL;
+ return 0;
+ }
+
+ for (tmp = srs->node->rules; tmp; tmp = tmp->next)
+ count++;
+
+ return count;
+}
+
+int qpol_avrule_get_syn_avrule_iter(const qpol_policy_t * policy, const struct qpol_avrule *rule, qpol_iterator_t ** iter)
+{
+ qpol_syn_rule_key_t *key = NULL;
+ const qpol_type_t *tmp_type;
+ const qpol_class_t *tmp_class;
+ const qpol_cond_t *tmp_cond;
+ syn_rule_state_t *srs = NULL;
+ uint32_t tmp_val;
+ int error = 0;
+
+ if (iter)
+ *iter = NULL;
+
+ if (!policy || !policy->ext || !rule || !iter) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* build key */
+ if (!(key = calloc(1, sizeof(qpol_syn_rule_key_t)))) {
+ error = errno;
+ ERR(policy, "%S", strerror(error));
+ goto err;
+ }
+
+ if (qpol_avrule_get_rule_type(policy, rule, &tmp_val)) {
+ error = errno;
+ goto err;
+ }
+ key->rule_type = (tmp_val == QPOL_RULE_DONTAUDIT ? (AVRULE_AUDITDENY | AVRULE_DONTAUDIT) : tmp_val);
+
+ if (qpol_avrule_get_source_type(policy, rule, &tmp_type)) {
+ error = errno;
+ goto err;
+ }
+ if (qpol_type_get_value(policy, tmp_type, &tmp_val)) {
+ error = errno;
+ goto err;
+ }
+ key->source_val = tmp_val;
+
+ if (qpol_avrule_get_target_type(policy, rule, &tmp_type)) {
+ error = errno;
+ goto err;
+ }
+ if (qpol_type_get_value(policy, tmp_type, &tmp_val)) {
+ error = errno;
+ goto err;
+ }
+ key->target_val = tmp_val;
+
+ if (qpol_avrule_get_object_class(policy, rule, &tmp_class)) {
+ error = errno;
+ goto err;
+ }
+ if (qpol_class_get_value(policy, tmp_class, &tmp_val)) {
+ error = errno;
+ goto err;
+ }
+ key->class_val = tmp_val;
+
+ if (qpol_avrule_get_cond(policy, rule, &tmp_cond)) {
+ error = errno;
+ goto err;
+ }
+ key->cond = (cond_node_t *) tmp_cond;
+
+ /* build state object */
+ if (!(srs = calloc(1, sizeof(syn_rule_state_t)))) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto err;
+ }
+
+ srs->node = qpol_syn_rule_table_find_node_by_key(policy->ext->syn_rule_table, key);
+ if (!srs->node) {
+ ERR(policy, "%s", "Unable to locate syntactic rules for semantic av rule");
+ errno = ENOENT;
+ goto err;
+ }
+ srs->cur = srs->node->rules;
+
+ if (qpol_iterator_create(policy, (void *)srs,
+ syn_rule_state_get_cur, syn_rule_state_next, syn_rule_state_end, syn_rule_state_size, free, iter))
+ {
+ error = errno;
+ goto err;
+ }
+
+ free(key);
+
+ return 0;
+
+ err:
+ free(key);
+ free(srs);
+ errno = error;
+ return -1;
+}
+
+int qpol_terule_get_syn_terule_iter(const qpol_policy_t * policy, const struct qpol_terule *rule, qpol_iterator_t ** iter)
+{
+ qpol_syn_rule_key_t *key = NULL;
+ const qpol_type_t *tmp_type;
+ const qpol_class_t *tmp_class;
+ const qpol_cond_t *tmp_cond;
+ syn_rule_state_t *srs = NULL;
+ uint32_t tmp_val;
+ int error = 0;
+
+ if (iter)
+ *iter = NULL;
+
+ if (!policy || !policy->ext || !rule || !iter) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* build key */
+ if (!(key = calloc(1, sizeof(qpol_syn_rule_key_t)))) {
+ error = errno;
+ ERR(policy, "%S", strerror(error));
+ goto err;
+ }
+
+ if (qpol_terule_get_rule_type(policy, rule, &tmp_val)) {
+ error = errno;
+ goto err;
+ }
+ key->rule_type = tmp_val;
+
+ if (qpol_terule_get_source_type(policy, rule, &tmp_type)) {
+ error = errno;
+ goto err;
+ }
+ if (qpol_type_get_value(policy, tmp_type, &tmp_val)) {
+ error = errno;
+ goto err;
+ }
+ key->source_val = tmp_val;
+
+ if (qpol_terule_get_target_type(policy, rule, &tmp_type)) {
+ error = errno;
+ goto err;
+ }
+ if (qpol_type_get_value(policy, tmp_type, &tmp_val)) {
+ error = errno;
+ goto err;
+ }
+ key->target_val = tmp_val;
+
+ if (qpol_terule_get_object_class(policy, rule, &tmp_class)) {
+ error = errno;
+ goto err;
+ }
+ if (qpol_class_get_value(policy, tmp_class, &tmp_val)) {
+ error = errno;
+ goto err;
+ }
+ key->class_val = tmp_val;
+
+ if (qpol_terule_get_cond(policy, rule, &tmp_cond)) {
+ error = errno;
+ goto err;
+ }
+ key->cond = (cond_node_t *) tmp_cond;
+
+ /* build state object */
+ if (!(srs = calloc(1, sizeof(syn_rule_state_t)))) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto err;
+ }
+
+ srs->node = qpol_syn_rule_table_find_node_by_key(policy->ext->syn_rule_table, key);
+ if (!srs->node) {
+ ERR(policy, "%s", "Unable to locate syntactic rules for semantic te rule");
+ error = ENOENT;
+ goto err;
+ }
+ srs->cur = srs->node->rules;
+
+ if (qpol_iterator_create(policy, (void *)srs,
+ syn_rule_state_get_cur, syn_rule_state_next, syn_rule_state_end, syn_rule_state_size, free, iter))
+ {
+ error = errno;
+ goto err;
+ }
+
+ free(key);
+
+ return 0;
+
+ err:
+ free(key);
+ free(srs);
+ errno = error;
+ return -1;
+}
diff --git a/libqpol/src/policy_parse.y b/libqpol/src/policy_parse.y
new file mode 100644
index 0000000..84f4114
--- /dev/null
+++ b/libqpol/src/policy_parse.y
@@ -0,0 +1,834 @@
+/**
+ * @file policy_parse.y
+ *
+ * This file is based upon checkpolicy/policy_parse.y from NSA's SVN
+ * repository. It has been modified to support older policy formats.
+ */
+
+/*
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ */
+
+/*
+ * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
+ *
+ * Support for enhanced MLS infrastructure.
+ *
+ * Updated: David Caplan, <dac@tresys.com>
+ *
+ * Added conditional policy language extensions
+ *
+ * Updated: Joshua Brindle <jbrindle@tresys.com>
+ * Karl MacMillan <kmacmillan@mentalrootkit.com>
+ * Jason Tang <jtang@tresys.com>
+ *
+ * Added support for binary policy modules
+ *
+ * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ * Copyright (C) 2003 - 2008 Tresys Technology, LLC
+ * Copyright (C) 2007 Red Hat Inc.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2.
+ */
+
+/* FLASK */
+
+%{
+#include <config.h>
+
+#include <sys/types.h>
+#include <assert.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+
+#include <sepol/policydb/expand.h>
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/services.h>
+#include <sepol/policydb/conditional.h>
+#include <sepol/policydb/flask.h>
+#include <sepol/policydb/hierarchy.h>
+#ifdef HAVE_SEPOL_POLICYCAPS
+#include <sepol/policydb/polcaps.h>
+#endif
+
+#include "queue.h"
+#include <qpol/policy.h>
+#include "module_compiler.h"
+#include "policy_define.h"
+
+extern policydb_t *policydbp;
+extern unsigned int pass;
+
+extern char yytext[];
+extern int yylex(void);
+extern int yywarn(char *msg);
+extern int yyerror(char *msg);
+
+typedef int (* require_func_t)();
+
+/* redefine input so we can read from a string */
+/* borrowed from O'Reilly lex and yacc pg 157 */
+extern char qpol_src_input[];
+extern char *qpol_src_inputptr;/* current position in qpol_src_input */
+extern char *qpol_src_inputlim;/* end of data */
+
+%}
+
+%union {
+ unsigned int val;
+ uintptr_t valptr;
+ void *ptr;
+ require_func_t require_func;
+}
+
+%type <ptr> cond_expr cond_expr_prim cond_pol_list cond_else
+%type <ptr> cond_allow_def cond_auditallow_def cond_auditdeny_def cond_dontaudit_def
+%type <ptr> cond_transition_def cond_te_avtab_def cond_rule_def
+%type <ptr> role_def roles
+%type <valptr> cexpr cexpr_prim op role_mls_op
+%type <val> ipv4_addr_def number
+%type <require_func> require_decl_def
+
+%token PATH
+%token CLONE
+%token COMMON
+%token CLASS
+%token CONSTRAIN
+%token VALIDATETRANS
+%token INHERITS
+%token SID
+%token ROLE
+%token ROLES
+%token TYPEALIAS
+%token TYPEATTRIBUTE
+%token TYPEBOUNDS
+%token TYPE
+%token TYPES
+%token ALIAS
+%token ATTRIBUTE
+%token BOOL
+%token IF
+%token ELSE
+%token TYPE_TRANSITION
+%token TYPE_MEMBER
+%token TYPE_CHANGE
+%token ROLE_TRANSITION
+%token RANGE_TRANSITION
+%token SENSITIVITY
+%token DOMINANCE
+%token DOM DOMBY INCOMP
+%token CATEGORY
+%token LEVEL
+%token RANGE
+%token MLSCONSTRAIN
+%token MLSVALIDATETRANS
+%token USER
+%token NEVERALLOW
+%token ALLOW
+%token AUDITALLOW
+%token AUDITDENY
+%token DONTAUDIT
+%token SOURCE
+%token TARGET
+%token SAMEUSER
+%token FSCON PORTCON NETIFCON NODECON
+%token PIRQCON IOMEMCON IOPORTCON PCIDEVICECON
+%token FSUSEXATTR FSUSETASK FSUSETRANS FSUSEPSID
+%token GENFSCON
+%token U1 U2 U3 R1 R2 R3 T1 T2 T3 L1 L2 H1 H2
+%token NOT AND OR XOR
+%token CTRUE CFALSE
+%token IDENTIFIER
+%token NUMBER
+%token EQUALS
+%token NOTEQUAL
+%token IPV4_ADDR
+%token IPV6_ADDR
+%token MODULE VERSION_IDENTIFIER REQUIRE OPTIONAL
+%token POLICYCAP
+%token PERMISSIVE
+
+%left OR
+%left XOR
+%left AND
+%right NOT
+%left EQUALS NOTEQUAL
+%%
+policy : base_policy
+ | module_policy
+ ;
+base_policy : { if (define_policy(pass, 0) == -1) return -1; }
+ classes initial_sids access_vectors
+ { if (pass == 1) { if (policydb_index_classes(policydbp)) return -1; }
+ else if (pass == 2) { if (policydb_index_others(NULL, policydbp, 0)) return -1; }}
+ opt_mls te_rbac users opt_constraints
+ { if (pass == 1) { if (policydb_index_bools(policydbp)) return -1;}
+ else if (pass == 2) { if (policydb_index_others(NULL, policydbp, 0)) return -1;}}
+ initial_sid_contexts opt_fs_contexts opt_fs_uses opt_genfs_contexts net_contexts opt_dev_contexts
+ ;
+classes : class_def
+ | classes class_def
+ ;
+class_def : CLASS identifier
+ {if (define_class()) return -1;}
+ ;
+initial_sids : initial_sid_def
+ | initial_sids initial_sid_def
+ ;
+initial_sid_def : SID identifier
+ {if (define_initial_sid()) return -1;}
+ ;
+access_vectors : opt_common_perms av_perms
+ ;
+opt_common_perms : common_perms
+ |
+ ;
+common_perms : common_perms_def
+ | common_perms common_perms_def
+ ;
+common_perms_def : COMMON identifier '{' identifier_list '}'
+ {if (define_common_perms()) return -1;}
+ ;
+av_perms : av_perms_def
+ | av_perms av_perms_def
+ ;
+av_perms_def : CLASS identifier '{' identifier_list '}'
+ {if (define_av_perms(FALSE)) return -1;}
+ | CLASS identifier INHERITS identifier
+ {if (define_av_perms(TRUE)) return -1;}
+ | CLASS identifier INHERITS identifier '{' identifier_list '}'
+ {if (define_av_perms(TRUE)) return -1;}
+ ;
+opt_mls : mls
+ |
+ ;
+mls : sensitivities dominance opt_categories levels mlspolicy
+ ;
+sensitivities : sensitivity_def
+ | sensitivities sensitivity_def
+ ;
+/* Need to call define_mls here, as we are working with files */
+/* only, not command line options */
+sensitivity_def : SENSITIVITY identifier alias_def ';'
+ {if (define_mls() | define_sens()) return -1;}
+ | SENSITIVITY identifier ';'
+ {if (define_mls() | define_sens()) return -1;}
+ ;
+alias_def : ALIAS names
+ ;
+dominance : DOMINANCE identifier
+ {if (define_dominance()) return -1;}
+ | DOMINANCE '{' identifier_list '}'
+ {if (define_dominance()) return -1;}
+ ;
+opt_categories : categories
+ |
+ ;
+categories : category_def
+ | categories category_def
+ ;
+category_def : CATEGORY identifier alias_def ';'
+ {if (define_category()) return -1;}
+ | CATEGORY identifier ';'
+ {if (define_category()) return -1;}
+ ;
+levels : level_def
+ | levels level_def
+ ;
+level_def : LEVEL identifier ':' id_comma_list ';'
+ {if (define_level()) return -1;}
+ | LEVEL identifier ';'
+ {if (define_level()) return -1;}
+ ;
+mlspolicy : mlspolicy_decl
+ | mlspolicy mlspolicy_decl
+ ;
+mlspolicy_decl : mlsconstraint_def
+ | mlsvalidatetrans_def
+ ;
+mlsconstraint_def : MLSCONSTRAIN names names cexpr ';'
+ { if (define_constraint((constraint_expr_t*)$4)) return -1; }
+ ;
+mlsvalidatetrans_def : MLSVALIDATETRANS names cexpr ';'
+ { if (define_validatetrans((constraint_expr_t*)$3)) return -1; }
+ ;
+te_rbac : te_rbac_decl
+ | te_rbac te_rbac_decl
+ ;
+te_rbac_decl : te_decl
+ | rbac_decl
+ | cond_stmt_def
+ | optional_block
+ | policycap_def
+ | ';'
+ ;
+rbac_decl : role_type_def
+ | role_dominance
+ | role_trans_def
+ | role_allow_def
+ ;
+te_decl : attribute_def
+ | type_def
+ | typealias_def
+ | typeattribute_def
+ | typebounds_def
+ | bool_def
+ | transition_def
+ | range_trans_def
+ | te_avtab_def
+ | permissive_def
+ ;
+attribute_def : ATTRIBUTE identifier ';'
+ { if (define_attrib()) return -1;}
+ ;
+type_def : TYPE identifier alias_def opt_attr_list ';'
+ {if (define_type(1)) return -1;}
+ | TYPE identifier opt_attr_list ';'
+ {if (define_type(0)) return -1;}
+ ;
+typealias_def : TYPEALIAS identifier alias_def ';'
+ {if (define_typealias()) return -1;}
+ ;
+typeattribute_def : TYPEATTRIBUTE identifier id_comma_list ';'
+ {if (define_typeattribute()) return -1;}
+ ;
+typebounds_def : TYPEBOUNDS identifier id_comma_list ';'
+ {if (define_typebounds()) return -1;}
+ ;
+opt_attr_list : ',' id_comma_list
+ |
+ ;
+bool_def : BOOL identifier bool_val ';'
+ {if (define_bool()) return -1;}
+ ;
+bool_val : CTRUE
+ { if (insert_id("T",0)) return -1; }
+ | CFALSE
+ { if (insert_id("F",0)) return -1; }
+ ;
+cond_stmt_def : IF cond_expr '{' cond_pol_list '}' cond_else
+ { if (pass == 2) { if (define_conditional((cond_expr_t*)$2, (avrule_t*)$4, (avrule_t*)$6) < 0) return -1; }}
+ ;
+cond_else : ELSE '{' cond_pol_list '}'
+ { $$ = $3; }
+ | /* empty */
+ { $$ = NULL; }
+cond_expr : '(' cond_expr ')'
+ { $$ = $2;}
+ | NOT cond_expr
+ { $$ = define_cond_expr(COND_NOT, $2, 0);
+ if ($$ == 0) return -1; }
+ | cond_expr AND cond_expr
+ { $$ = define_cond_expr(COND_AND, $1, $3);
+ if ($$ == 0) return -1; }
+ | cond_expr OR cond_expr
+ { $$ = define_cond_expr(COND_OR, $1, $3);
+ if ($$ == 0) return -1; }
+ | cond_expr XOR cond_expr
+ { $$ = define_cond_expr(COND_XOR, $1, $3);
+ if ($$ == 0) return -1; }
+ | cond_expr EQUALS cond_expr
+ { $$ = define_cond_expr(COND_EQ, $1, $3);
+ if ($$ == 0) return -1; }
+ | cond_expr NOTEQUAL cond_expr
+ { $$ = define_cond_expr(COND_NEQ, $1, $3);
+ if ($$ == 0) return -1; }
+ | cond_expr_prim
+ { $$ = $1; }
+ ;
+cond_expr_prim : identifier
+ { $$ = define_cond_expr(COND_BOOL,0, 0);
+ if ($$ == COND_ERR) return -1; }
+ ;
+cond_pol_list : cond_pol_list cond_rule_def
+ { $$ = define_cond_pol_list((avrule_t *)$1, (avrule_t *)$2); }
+ | /* empty */
+ { $$ = NULL; }
+ ;
+cond_rule_def : cond_transition_def
+ { $$ = $1; }
+ | cond_te_avtab_def
+ { $$ = $1; }
+ | require_block
+ { $$ = NULL; }
+ ;
+cond_transition_def : TYPE_TRANSITION names names ':' names identifier ';'
+ { $$ = define_cond_compute_type(AVRULE_TRANSITION) ;
+ if ($$ == COND_ERR) return -1;}
+ | TYPE_MEMBER names names ':' names identifier ';'
+ { $$ = define_cond_compute_type(AVRULE_MEMBER) ;
+ if ($$ == COND_ERR) return -1;}
+ | TYPE_CHANGE names names ':' names identifier ';'
+ { $$ = define_cond_compute_type(AVRULE_CHANGE) ;
+ if ($$ == COND_ERR) return -1;}
+ ;
+cond_te_avtab_def : cond_allow_def
+ { $$ = $1; }
+ | cond_auditallow_def
+ { $$ = $1; }
+ | cond_auditdeny_def
+ { $$ = $1; }
+ | cond_dontaudit_def
+ { $$ = $1; }
+ ;
+cond_allow_def : ALLOW names names ':' names names ';'
+ { $$ = define_cond_te_avtab(AVRULE_ALLOWED) ;
+ if ($$ == COND_ERR) return -1; }
+ ;
+cond_auditallow_def : AUDITALLOW names names ':' names names ';'
+ { $$ = define_cond_te_avtab(AVRULE_AUDITALLOW) ;
+ if ($$ == COND_ERR) return -1; }
+ ;
+cond_auditdeny_def : AUDITDENY names names ':' names names ';'
+ { $$ = define_cond_te_avtab(AVRULE_AUDITDENY) ;
+ if ($$ == COND_ERR) return -1; }
+ ;
+cond_dontaudit_def : DONTAUDIT names names ':' names names ';'
+ { $$ = define_cond_te_avtab(AVRULE_DONTAUDIT);
+ if ($$ == COND_ERR) return -1; }
+ ;
+transition_def : TYPE_TRANSITION names names ':' names identifier ';'
+ {if (define_compute_type(AVRULE_TRANSITION)) return -1;}
+ | TYPE_MEMBER names names ':' names identifier ';'
+ {if (define_compute_type(AVRULE_MEMBER)) return -1;}
+ | TYPE_CHANGE names names ':' names identifier ';'
+ {if (define_compute_type(AVRULE_CHANGE)) return -1;}
+ ;
+range_trans_def : RANGE_TRANSITION names names mls_range_def ';'
+ { if (define_range_trans(0)) return -1; }
+ | RANGE_TRANSITION names names ':' names mls_range_def ';'
+ { if (define_range_trans(1)) return -1; }
+ ;
+te_avtab_def : allow_def
+ | auditallow_def
+ | auditdeny_def
+ | dontaudit_def
+ | neverallow_def
+ ;
+allow_def : ALLOW names names ':' names names ';'
+ {if (define_te_avtab(AVRULE_ALLOWED)) return -1; }
+ ;
+auditallow_def : AUDITALLOW names names ':' names names ';'
+ {if (define_te_avtab(AVRULE_AUDITALLOW)) return -1; }
+ ;
+auditdeny_def : AUDITDENY names names ':' names names ';'
+ {if (define_te_avtab(AVRULE_AUDITDENY)) return -1; }
+ ;
+dontaudit_def : DONTAUDIT names names ':' names names ';'
+ {if (define_te_avtab(AVRULE_DONTAUDIT)) return -1; }
+ ;
+neverallow_def : NEVERALLOW names names ':' names names ';'
+ {if (define_te_avtab(AVRULE_NEVERALLOW)) return -1; }
+ ;
+role_type_def : ROLE identifier TYPES names ';'
+ {if (define_role_types()) return -1;}
+ | ROLE identifier';'
+ {if (define_role_types()) return -1;}
+ ;
+role_dominance : DOMINANCE '{' roles '}'
+ ;
+role_trans_def : ROLE_TRANSITION names names identifier ';'
+ {if (define_role_trans()) return -1; }
+ ;
+role_allow_def : ALLOW names names ';'
+ {if (define_role_allow()) return -1; }
+ ;
+roles : role_def
+ { $$ = $1; }
+ | roles role_def
+ { $$ = merge_roles_dom((role_datum_t*)$1, (role_datum_t*)$2); if ($$ == 0) return -1;}
+ ;
+role_def : ROLE identifier_push ';'
+ {$$ = define_role_dom(NULL); if ($$ == 0) return -1;}
+ | ROLE identifier_push '{' roles '}'
+ {$$ = define_role_dom((role_datum_t*)$4); if ($$ == 0) return -1;}
+ ;
+opt_constraints : constraints
+ |
+ ;
+constraints : constraint_decl
+ | constraints constraint_decl
+ ;
+constraint_decl : constraint_def
+ | validatetrans_def
+ ;
+constraint_def : CONSTRAIN names names cexpr ';'
+ { if (define_constraint((constraint_expr_t*)$4)) return -1; }
+ ;
+validatetrans_def : VALIDATETRANS names cexpr ';'
+ { if (define_validatetrans((constraint_expr_t*)$3)) return -1; }
+ ;
+cexpr : '(' cexpr ')'
+ { $$ = $2; }
+ | NOT cexpr
+ { $$ = define_cexpr(CEXPR_NOT, $2, 0);
+ if ($$ == 0) return -1; }
+ | cexpr AND cexpr
+ { $$ = define_cexpr(CEXPR_AND, $1, $3);
+ if ($$ == 0) return -1; }
+ | cexpr OR cexpr
+ { $$ = define_cexpr(CEXPR_OR, $1, $3);
+ if ($$ == 0) return -1; }
+ | cexpr_prim
+ { $$ = $1; }
+ ;
+cexpr_prim : U1 op U2
+ { $$ = define_cexpr(CEXPR_ATTR, CEXPR_USER, $2);
+ if ($$ == 0) return -1; }
+ | R1 role_mls_op R2
+ { $$ = define_cexpr(CEXPR_ATTR, CEXPR_ROLE, $2);
+ if ($$ == 0) return -1; }
+ | T1 op T2
+ { $$ = define_cexpr(CEXPR_ATTR, CEXPR_TYPE, $2);
+ if ($$ == 0) return -1; }
+ | U1 op { if (insert_separator(1)) return -1; } names_push
+ { $$ = define_cexpr(CEXPR_NAMES, CEXPR_USER, $2);
+ if ($$ == 0) return -1; }
+ | U2 op { if (insert_separator(1)) return -1; } names_push
+ { $$ = define_cexpr(CEXPR_NAMES, (CEXPR_USER | CEXPR_TARGET), $2);
+ if ($$ == 0) return -1; }
+ | U3 op { if (insert_separator(1)) return -1; } names_push
+ { $$ = define_cexpr(CEXPR_NAMES, (CEXPR_USER | CEXPR_XTARGET), $2);
+ if ($$ == 0) return -1; }
+ | R1 op { if (insert_separator(1)) return -1; } names_push
+ { $$ = define_cexpr(CEXPR_NAMES, CEXPR_ROLE, $2);
+ if ($$ == 0) return -1; }
+ | R2 op { if (insert_separator(1)) return -1; } names_push
+ { $$ = define_cexpr(CEXPR_NAMES, (CEXPR_ROLE | CEXPR_TARGET), $2);
+ if ($$ == 0) return -1; }
+ | R3 op { if (insert_separator(1)) return -1; } names_push
+ { $$ = define_cexpr(CEXPR_NAMES, (CEXPR_ROLE | CEXPR_XTARGET), $2);
+ if ($$ == 0) return -1; }
+ | T1 op { if (insert_separator(1)) return -1; } names_push
+ { $$ = define_cexpr(CEXPR_NAMES, CEXPR_TYPE, $2);
+ if ($$ == 0) return -1; }
+ | T2 op { if (insert_separator(1)) return -1; } names_push
+ { $$ = define_cexpr(CEXPR_NAMES, (CEXPR_TYPE | CEXPR_TARGET), $2);
+ if ($$ == 0) return -1; }
+ | T3 op { if (insert_separator(1)) return -1; } names_push
+ { $$ = define_cexpr(CEXPR_NAMES, (CEXPR_TYPE | CEXPR_XTARGET), $2);
+ if ($$ == 0) return -1; }
+ | SAMEUSER
+ { $$ = define_cexpr(CEXPR_ATTR, CEXPR_USER, CEXPR_EQ);
+ if ($$ == 0) return -1; }
+ | SOURCE ROLE { if (insert_separator(1)) return -1; } names_push
+ { $$ = define_cexpr(CEXPR_NAMES, CEXPR_ROLE, CEXPR_EQ);
+ if ($$ == 0) return -1; }
+ | TARGET ROLE { if (insert_separator(1)) return -1; } names_push
+ { $$ = define_cexpr(CEXPR_NAMES, (CEXPR_ROLE | CEXPR_TARGET), CEXPR_EQ);
+ if ($$ == 0) return -1; }
+ | ROLE role_mls_op
+ { $$ = define_cexpr(CEXPR_ATTR, CEXPR_ROLE, $2);
+ if ($$ == 0) return -1; }
+ | SOURCE TYPE { if (insert_separator(1)) return -1; } names_push
+ { $$ = define_cexpr(CEXPR_NAMES, CEXPR_TYPE, CEXPR_EQ);
+ if ($$ == 0) return -1; }
+ | TARGET TYPE { if (insert_separator(1)) return -1; } names_push
+ { $$ = define_cexpr(CEXPR_NAMES, (CEXPR_TYPE | CEXPR_TARGET), CEXPR_EQ);
+ if ($$ == 0) return -1; }
+ | L1 role_mls_op L2
+ { $$ = define_cexpr(CEXPR_ATTR, CEXPR_L1L2, $2);
+ if ($$ == 0) return -1; }
+ | L1 role_mls_op H2
+ { $$ = define_cexpr(CEXPR_ATTR, CEXPR_L1H2, $2);
+ if ($$ == 0) return -1; }
+ | H1 role_mls_op L2
+ { $$ = define_cexpr(CEXPR_ATTR, CEXPR_H1L2, $2);
+ if ($$ == 0) return -1; }
+ | H1 role_mls_op H2
+ { $$ = define_cexpr(CEXPR_ATTR, CEXPR_H1H2, $2);
+ if ($$ == 0) return -1; }
+ | L1 role_mls_op H1
+ { $$ = define_cexpr(CEXPR_ATTR, CEXPR_L1H1, $2);
+ if ($$ == 0) return -1; }
+ | L2 role_mls_op H2
+ { $$ = define_cexpr(CEXPR_ATTR, CEXPR_L2H2, $2);
+ if ($$ == 0) return -1; }
+ ;
+op : EQUALS
+ { $$ = CEXPR_EQ; }
+ | NOTEQUAL
+ { $$ = CEXPR_NEQ; }
+ ;
+role_mls_op : op
+ { $$ = $1; }
+ | DOM
+ { $$ = CEXPR_DOM; }
+ | DOMBY
+ { $$ = CEXPR_DOMBY; }
+ | INCOMP
+ { $$ = CEXPR_INCOMP; }
+ ;
+users : user_def
+ | users user_def
+ ;
+user_def : USER identifier ROLES names opt_mls_user ';'
+ {if (define_user()) return -1;}
+ ;
+opt_mls_user : LEVEL mls_level_def RANGE mls_range_def
+ |
+ ;
+initial_sid_contexts : initial_sid_context_def
+ | initial_sid_contexts initial_sid_context_def
+ ;
+initial_sid_context_def : SID identifier security_context_def
+ {if (define_initial_sid_context()) return -1;}
+ ;
+opt_dev_contexts : dev_contexts |
+ ;
+dev_contexts : dev_context_def
+ | dev_contexts dev_context_def
+ ;
+dev_context_def : pirq_context_def |
+ iomem_context_def |
+ ioport_context_def |
+ pci_context_def
+ ;
+pirq_context_def : PIRQCON number security_context_def
+ {if (define_pirq_context($2)) return -1;}
+ ;
+iomem_context_def : IOMEMCON number security_context_def
+ {if (define_iomem_context($2,$2)) return -1;}
+ | IOMEMCON number '-' number security_context_def
+ {if (define_iomem_context($2,$4)) return -1;}
+ ;
+ioport_context_def : IOPORTCON number security_context_def
+ {if (define_ioport_context($2,$2)) return -1;}
+ | IOPORTCON number '-' number security_context_def
+ {if (define_ioport_context($2,$4)) return -1;}
+ ;
+pci_context_def : PCIDEVICECON number security_context_def
+ {if (define_pcidevice_context($2)) return -1;}
+ ;
+opt_fs_contexts : fs_contexts
+ |
+ ;
+fs_contexts : fs_context_def
+ | fs_contexts fs_context_def
+ ;
+fs_context_def : FSCON number number security_context_def security_context_def
+ {if (define_fs_context($2,$3)) return -1;}
+ ;
+net_contexts : opt_port_contexts opt_netif_contexts opt_node_contexts
+ ;
+opt_port_contexts : port_contexts
+ |
+ ;
+port_contexts : port_context_def
+ | port_contexts port_context_def
+ ;
+port_context_def : PORTCON identifier number security_context_def
+ {if (define_port_context($3,$3)) return -1;}
+ | PORTCON identifier number '-' number security_context_def
+ {if (define_port_context($3,$5)) return -1;}
+ ;
+opt_netif_contexts : netif_contexts
+ |
+ ;
+netif_contexts : netif_context_def
+ | netif_contexts netif_context_def
+ ;
+netif_context_def : NETIFCON identifier security_context_def security_context_def
+ {if (define_netif_context()) return -1;}
+ ;
+opt_node_contexts : node_contexts
+ |
+ ;
+node_contexts : node_context_def
+ | node_contexts node_context_def
+ ;
+node_context_def : NODECON ipv4_addr_def ipv4_addr_def security_context_def
+ {if (define_ipv4_node_context()) return -1;}
+ | NODECON ipv6_addr ipv6_addr security_context_def
+ {if (define_ipv6_node_context()) return -1;}
+ ;
+opt_fs_uses : fs_uses
+ |
+ ;
+fs_uses : fs_use_def
+ | fs_uses fs_use_def
+ ;
+fs_use_def : FSUSEXATTR identifier security_context_def ';'
+ {if (define_fs_use(SECURITY_FS_USE_XATTR)) return -1;}
+ | FSUSETASK identifier security_context_def ';'
+ {if (define_fs_use(SECURITY_FS_USE_TASK)) return -1;}
+ | FSUSETRANS identifier security_context_def ';'
+ {if (define_fs_use(SECURITY_FS_USE_TRANS)) return -1;}
+ | FSUSEPSID identifier ';'
+ {if (define_fs_use(SECURITY_FS_USE_PSIDS)) return -1;}
+ ;
+opt_genfs_contexts : genfs_contexts
+ |
+ ;
+genfs_contexts : genfs_context_def
+ | genfs_contexts genfs_context_def
+ ;
+genfs_context_def : GENFSCON identifier path '-' identifier security_context_def
+ {if (define_genfs_context(1)) return -1;}
+ | GENFSCON identifier path '-' '-' {insert_id("-", 0);} security_context_def
+ {if (define_genfs_context(1)) return -1;}
+ | GENFSCON identifier path security_context_def
+ {if (define_genfs_context(0)) return -1;}
+ ;
+ipv4_addr_def : IPV4_ADDR
+ { if (insert_id(yytext,0)) return -1; }
+ ;
+security_context_def : identifier ':' identifier ':' identifier opt_mls_range_def
+ ;
+opt_mls_range_def : ':' mls_range_def
+ |
+ ;
+mls_range_def : mls_level_def '-' mls_level_def
+ {if (insert_separator(0)) return -1;}
+ | mls_level_def
+ {if (insert_separator(0)) return -1;}
+ ;
+mls_level_def : identifier ':' id_comma_list
+ {if (insert_separator(0)) return -1;}
+ | identifier
+ {if (insert_separator(0)) return -1;}
+ ;
+id_comma_list : identifier
+ | id_comma_list ',' identifier
+ ;
+tilde : '~'
+ ;
+asterisk : '*'
+ ;
+names : identifier
+ { if (insert_separator(0)) return -1; }
+ | nested_id_set
+ { if (insert_separator(0)) return -1; }
+ | asterisk
+ { if (insert_id("*", 0)) return -1;
+ if (insert_separator(0)) return -1; }
+ | tilde identifier
+ { if (insert_id("~", 0)) return -1;
+ if (insert_separator(0)) return -1; }
+ | tilde nested_id_set
+ { if (insert_id("~", 0)) return -1;
+ if (insert_separator(0)) return -1; }
+ | identifier '-' { if (insert_id("-", 0)) return -1; } identifier
+ { if (insert_separator(0)) return -1; }
+ ;
+tilde_push : tilde
+ { if (insert_id("~", 1)) return -1; }
+ ;
+asterisk_push : asterisk
+ { if (insert_id("*", 1)) return -1; }
+ ;
+names_push : identifier_push
+ | '{' identifier_list_push '}'
+ | asterisk_push
+ | tilde_push identifier_push
+ | tilde_push '{' identifier_list_push '}'
+ ;
+identifier_list_push : identifier_push
+ | identifier_list_push identifier_push
+ ;
+identifier_push : IDENTIFIER
+ { if (insert_id(yytext, 1)) return -1; }
+ ;
+identifier_list : identifier
+ | identifier_list identifier
+ ;
+nested_id_set : '{' nested_id_list '}'
+ ;
+nested_id_list : nested_id_element | nested_id_list nested_id_element
+ ;
+nested_id_element : identifier | '-' { if (insert_id("-", 0)) return -1; } identifier | nested_id_set
+ ;
+identifier : IDENTIFIER
+ { if (insert_id(yytext,0)) return -1; }
+ ;
+path : PATH
+ { if (insert_id(yytext,0)) return -1; }
+ ;
+number : NUMBER
+ { $$ = strtoul(yytext,NULL,0); }
+ ;
+ipv6_addr : IPV6_ADDR
+ { if (insert_id(yytext,0)) return -1; }
+ ;
+policycap_def : POLICYCAP identifier ';'
+ {if (define_polcap()) return -1;}
+ ;
+permissive_def : PERMISSIVE identifier ';'
+ {if (define_permissive()) return -1;}
+
+/*********** module grammar below ***********/
+
+module_policy : module_def avrules_block
+ { if (end_avrule_block(pass) == -1) return -1;
+ if (policydb_index_others(NULL, policydbp, 0)) return -1;
+ }
+ ;
+module_def : MODULE identifier version_identifier ';'
+ { if (define_policy(pass, 1) == -1) return -1; }
+ ;
+version_identifier : VERSION_IDENTIFIER
+ { if (insert_id(yytext,0)) return -1; }
+ | ipv4_addr_def /* version can look like ipv4 address */
+ ;
+avrules_block : avrule_decls avrule_user_defs
+ ;
+avrule_decls : avrule_decls avrule_decl
+ | avrule_decl
+ ;
+avrule_decl : rbac_decl
+ | te_decl
+ | cond_stmt_def
+ | require_block
+ | optional_block
+ | ';'
+ ;
+require_block : REQUIRE '{' require_list '}'
+ ;
+require_list : require_list require_decl
+ | require_decl
+ ;
+require_decl : require_class ';'
+ | require_decl_def require_id_list ';'
+ ;
+require_class : CLASS identifier names
+ { if (require_class(pass)) return -1; }
+ ;
+require_decl_def : ROLE { $$ = require_role; }
+ | TYPE { $$ = require_type; }
+ | ATTRIBUTE { $$ = require_attribute; }
+ | USER { $$ = require_user; }
+ | BOOL { $$ = require_bool; }
+ | SENSITIVITY { $$ = require_sens; }
+ | CATEGORY { $$ = require_cat; }
+ ;
+require_id_list : identifier
+ { if ($<require_func>0 (pass)) return -1; }
+ | require_id_list ',' identifier
+ { if ($<require_func>0 (pass)) return -1; }
+ ;
+optional_block : optional_decl '{' avrules_block '}'
+ { if (end_avrule_block(pass) == -1) return -1; }
+ optional_else
+ { if (end_optional(pass) == -1) return -1; }
+ ;
+optional_else : else_decl '{' avrules_block '}'
+ { if (end_avrule_block(pass) == -1) return -1; }
+ | /* empty */
+ ;
+optional_decl : OPTIONAL
+ { if (begin_optional(pass) == -1) return -1; }
+ ;
+else_decl : ELSE
+ { if (begin_optional_else(pass) == -1) return -1; }
+ ;
+avrule_user_defs : user_def avrule_user_defs
+ | /* empty */
+ ;
diff --git a/libqpol/src/policy_scan.l b/libqpol/src/policy_scan.l
new file mode 100644
index 0000000..75485f3
--- /dev/null
+++ b/libqpol/src/policy_scan.l
@@ -0,0 +1,320 @@
+/**
+ * @file policy_parse.y
+ *
+ * This file is based upon checkpolicy/policy_scan.l fram NSA's SVN
+ * repository. It has been modified to support older policy formats.
+ *
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ *
+ * Updated: David Caplan, <dac@tresys.com>
+ *
+ * Added conditional policy language extensions
+ *
+ * Jason Tang <jtang@tresys.com>
+ *
+ * Added support for binary policy modules
+ *
+ * Copyright (C) 2003-5 Tresys Technology, LLC
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2.
+ */
+
+/* FLASK */
+
+%{
+#undef YY_INPUT
+#define YY_INPUT(b, r, ms) (r = qpol_src_yyinput(b, ms))
+%}
+
+%{
+#include <sys/types.h>
+#include <limits.h>
+#include <stdint.h>
+#include <string.h>
+
+typedef int (* require_func_t)();
+
+#include "policy_parse.h"
+
+static char linebuf[2][255];
+static unsigned int lno = 0;
+int yywarn(char *msg);
+
+void set_source_file(const char *name);
+
+char source_file[PATH_MAX];
+unsigned long source_lineno = 1;
+
+unsigned long policydb_lineno = 1;
+
+unsigned int policydb_errors = 0;
+
+/* redefine input so we can read from a string */
+/* borrowed from O'Reilly lex and yacc pg 157 */
+extern char qpol_src_input[];
+extern char *qpol_src_inputptr;/* current position in myinput */
+extern char *qpol_src_inputlim;/* end of data */
+int qpol_src_yyinput(char *buf, int max_size);
+
+%}
+
+%option nounput
+%option noyywrap
+
+%array
+letter [A-Za-z]
+digit [0-9]
+alnum [a-zA-Z0-9]
+hexval [0-9A-Fa-f]
+
+%%
+\n.* { strncpy(linebuf[lno], yytext+1, 255);
+ linebuf[lno][254] = 0;
+ lno = 1 - lno;
+ policydb_lineno++;
+ source_lineno++;
+ yyless(1); }
+CLONE |
+clone { return(CLONE); }
+COMMON |
+common { return(COMMON); }
+CLASS |
+class { return(CLASS); }
+CONSTRAIN |
+constrain { return(CONSTRAIN); }
+VALIDATETRANS |
+validatetrans { return(VALIDATETRANS); }
+INHERITS |
+inherits { return(INHERITS); }
+SID |
+sid { return(SID); }
+ROLE |
+role { return(ROLE); }
+ROLES |
+roles { return(ROLES); }
+TYPES |
+types { return(TYPES); }
+TYPEALIAS |
+typealias { return(TYPEALIAS); }
+TYPEATTRIBUTE |
+typeattribute { return(TYPEATTRIBUTE); }
+TYPEBOUNDS |
+typebounds { return(TYPEBOUNDS); }
+TYPE |
+type { return(TYPE); }
+BOOL |
+bool { return(BOOL); }
+IF |
+if { return(IF); }
+ELSE |
+else { return(ELSE); }
+ALIAS |
+alias { return(ALIAS); }
+ATTRIBUTE |
+attribute { return(ATTRIBUTE); }
+TYPE_TRANSITION |
+type_transition { return(TYPE_TRANSITION); }
+TYPE_MEMBER |
+type_member { return(TYPE_MEMBER); }
+TYPE_CHANGE |
+type_change { return(TYPE_CHANGE); }
+ROLE_TRANSITION |
+role_transition { return(ROLE_TRANSITION); }
+RANGE_TRANSITION |
+range_transition { return(RANGE_TRANSITION); }
+SENSITIVITY |
+sensitivity { return(SENSITIVITY); }
+DOMINANCE |
+dominance { return(DOMINANCE); }
+CATEGORY |
+category { return(CATEGORY); }
+LEVEL |
+level { return(LEVEL); }
+RANGE |
+range { return(RANGE); }
+MLSCONSTRAIN |
+mlsconstrain { return(MLSCONSTRAIN); }
+MLSVALIDATETRANS |
+mlsvalidatetrans { return(MLSVALIDATETRANS); }
+USER |
+user { return(USER); }
+NEVERALLOW |
+neverallow { return(NEVERALLOW); }
+ALLOW |
+allow { return(ALLOW); }
+AUDITALLOW |
+auditallow { return(AUDITALLOW); }
+AUDITDENY |
+auditdeny { return(AUDITDENY); }
+DONTAUDIT |
+dontaudit { return(DONTAUDIT); }
+SOURCE |
+source { return(SOURCE); }
+TARGET |
+target { return(TARGET); }
+SAMEUSER |
+sameuser { return(SAMEUSER);}
+module|MODULE { return(MODULE); }
+require|REQUIRE { return(REQUIRE); }
+optional|OPTIONAL { return(OPTIONAL); }
+OR |
+or { return(OR);}
+AND |
+and { return(AND);}
+NOT |
+not { return(NOT);}
+xor |
+XOR { return(XOR); }
+eq |
+EQ { return(EQUALS);}
+true |
+TRUE { return(CTRUE); }
+false |
+FALSE { return(CFALSE); }
+dom |
+DOM { return(DOM);}
+domby |
+DOMBY { return(DOMBY);}
+INCOMP |
+incomp { return(INCOMP);}
+fscon |
+FSCON { return(FSCON);}
+portcon |
+PORTCON { return(PORTCON);}
+netifcon |
+NETIFCON { return(NETIFCON);}
+nodecon |
+NODECON { return(NODECON);}
+fs_use_psid |
+FS_USE_PSID { return(FSUSEPSID);}
+pirqcon |
+PIRQCON { return(PIRQCON);}
+iomemcon |
+IOMEMCON { return(IOMEMCON);}
+ioportcon |
+IOPORTCON { return(IOPORTCON);}
+pcidevicecon |
+PCIDEVICECON { return(PCIDEVICECON);}
+fs_use_xattr |
+FS_USE_XATTR { return(FSUSEXATTR);}
+fs_use_task |
+FS_USE_TASK { return(FSUSETASK);}
+fs_use_trans |
+FS_USE_TRANS { return(FSUSETRANS);}
+genfscon |
+GENFSCON { return(GENFSCON);}
+r1 |
+R1 { return(R1); }
+r2 |
+R2 { return(R2); }
+r3 |
+R3 { return(R3); }
+u1 |
+U1 { return(U1); }
+u2 |
+U2 { return(U2); }
+u3 |
+U3 { return(U3); }
+t1 |
+T1 { return(T1); }
+t2 |
+T2 { return(T2); }
+t3 |
+T3 { return(T3); }
+l1 |
+L1 { return(L1); }
+l2 |
+L2 { return(L2); }
+h1 |
+H1 { return(H1); }
+h2 |
+H2 { return(H2); }
+policycap |
+POLICYCAP { return(POLICYCAP); }
+permissive |
+PERMISSIVE { return(PERMISSIVE); }
+"/"({alnum}|[_\.\-/])* { return(PATH); }
+{letter}({alnum}|[_\-])*([\.]?({alnum}|[_\-]))* { return(IDENTIFIER); }
+{digit}+|0x{hexval}+ { return(NUMBER); }
+{digit}{1,3}(\.{digit}{1,3}){3} { return(IPV4_ADDR); }
+{hexval}{0,4}":"{hexval}{0,4}":"({hexval}|[:.])* { return(IPV6_ADDR); }
+{digit}+(\.({alnum}|[_.])*)? { return(VERSION_IDENTIFIER); }
+#line[ ]1[ ]\"[^\n]*\" { set_source_file(yytext+9); }
+#line[ ]{digit}+ { source_lineno = atoi(yytext+6)-1; }
+#[^\n]* { /* delete comments */ }
+[ \t\f]+ { /* delete whitespace */ }
+"==" { return(EQUALS); }
+"!=" { return (NOTEQUAL); }
+"&&" { return (AND); }
+"||" { return (OR); }
+"!" { return (NOT); }
+"^" { return (XOR); }
+"," |
+":" |
+";" |
+"(" |
+")" |
+"{" |
+"}" |
+"[" |
+"-" |
+"." |
+"]" |
+"~" |
+"*" { return(yytext[0]); }
+. { yywarn("unrecognized character");}
+%%
+int yyerror(char *msg)
+{
+ if (source_file[0])
+ fprintf(stderr, "%s:%ld:",
+ source_file, source_lineno);
+ else
+ fprintf(stderr, "(unknown source)::");
+ fprintf(stderr, "ERROR '%s' at token '%s' on line %ld:\n%s\n%s\n",
+ msg,
+ yytext,
+ policydb_lineno,
+ linebuf[0], linebuf[1]);
+ policydb_errors++;
+ return -1;
+}
+
+int yywarn(char *msg)
+{
+ if (source_file[0])
+ fprintf(stderr, "%s:%ld:",
+ source_file, source_lineno);
+ else
+ fprintf(stderr, "(unknown source)::");
+ fprintf(stderr, "WARNING '%s' at token '%s' on line %ld:\n%s\n%s\n",
+ msg,
+ yytext,
+ policydb_lineno,
+ linebuf[0], linebuf[1]);
+ return 0;
+}
+
+void set_source_file(const char *name)
+{
+ source_lineno = 1;
+ strncpy(source_file, name, sizeof(source_file)-1);
+ source_file[sizeof(source_file)-1] = '\0';
+}
+
+int qpol_src_yyinput(char *buf, int max_size)
+{
+ int n = max_size < (qpol_src_inputlim - qpol_src_inputptr) ? max_size : (qpol_src_inputlim - qpol_src_inputptr);
+ if (n > 0) {
+ memcpy(buf, qpol_src_inputptr, n);
+ qpol_src_inputptr += n;
+ }
+
+ return n;
+}
+
+void init_scanner(void)
+{
+ yy_flush_buffer(YY_CURRENT_BUFFER);
+}
diff --git a/libqpol/src/portcon_query.c b/libqpol/src/portcon_query.c
new file mode 100644
index 0000000..d48bd37
--- /dev/null
+++ b/libqpol/src/portcon_query.c
@@ -0,0 +1,183 @@
+/**
+ * @file
+ * Defines the public interface for searching and iterating over portcon statements.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @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
+ */
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <netinet/in.h>
+#include <qpol/iterator.h>
+#include <qpol/policy.h>
+#include <qpol/context_query.h>
+#include <qpol/portcon_query.h>
+#include <sepol/policydb/policydb.h>
+#include "qpol_internal.h"
+#include "iterator_internal.h"
+
+int qpol_policy_get_portcon_by_port(const qpol_policy_t * policy, uint16_t low, uint16_t high, uint8_t protocol,
+ const qpol_portcon_t ** ocon)
+{
+ ocontext_t *tmp = NULL;
+ policydb_t *db = NULL;
+
+ if (ocon != NULL)
+ *ocon = NULL;
+
+ if (policy == NULL || ocon == NULL) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+ for (tmp = db->ocontexts[OCON_PORT]; tmp; tmp = tmp->next) {
+ if (tmp->u.port.low_port == low && tmp->u.port.high_port == high && tmp->u.port.protocol == protocol)
+ break;
+ }
+
+ *ocon = (qpol_portcon_t *) tmp;
+
+ if (*ocon == NULL) {
+ ERR(policy, "could not find portcon statement for %u-%u:%u", low, high, protocol);
+ errno = ENOENT;
+ return STATUS_ERR;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_policy_get_portcon_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter)
+{
+ policydb_t *db = NULL;
+ int error = 0;
+ ocon_state_t *os = NULL;
+
+ if (iter != NULL)
+ *iter = NULL;
+
+ if (policy == NULL || iter == NULL) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+
+ os = calloc(1, sizeof(ocon_state_t));
+ if (os == NULL) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = error;
+ return STATUS_ERR;
+ }
+
+ os->head = os->cur = db->ocontexts[OCON_PORT];
+
+ if (qpol_iterator_create(policy, (void *)os, ocon_state_get_cur,
+ ocon_state_next, ocon_state_end, ocon_state_size, free, iter)) {
+ free(os);
+ return STATUS_ERR;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_portcon_get_protocol(const qpol_policy_t * policy, const qpol_portcon_t * ocon, uint8_t * protocol)
+{
+ ocontext_t *internal_ocon = NULL;
+
+ if (protocol != NULL)
+ *protocol = 0;
+
+ if (policy == NULL || ocon == NULL || protocol == NULL) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_ocon = (ocontext_t *) ocon;
+
+ *protocol = internal_ocon->u.port.protocol;
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_portcon_get_low_port(const qpol_policy_t * policy, const qpol_portcon_t * ocon, uint16_t * port)
+{
+ ocontext_t *internal_ocon = NULL;
+
+ if (port != NULL)
+ *port = 0;
+
+ if (policy == NULL || ocon == NULL || port == NULL) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_ocon = (ocontext_t *) ocon;
+
+ *port = internal_ocon->u.port.low_port;
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_portcon_get_high_port(const qpol_policy_t * policy, const qpol_portcon_t * ocon, uint16_t * port)
+{
+ ocontext_t *internal_ocon = NULL;
+
+ if (port != NULL)
+ *port = 0;
+
+ if (policy == NULL || ocon == NULL || port == NULL) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_ocon = (ocontext_t *) ocon;
+
+ *port = internal_ocon->u.port.high_port;
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_portcon_get_context(const qpol_policy_t * policy, const qpol_portcon_t * ocon, const qpol_context_t ** context)
+{
+ ocontext_t *internal_ocon = NULL;
+
+ if (context != NULL)
+ *context = NULL;
+
+ if (policy == NULL || ocon == NULL || context == NULL) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_ocon = (ocontext_t *) ocon;
+ *context = (qpol_context_t *) & (internal_ocon->context[0]);
+
+ return STATUS_SUCCESS;
+}
diff --git a/libqpol/src/qpol_internal.h b/libqpol/src/qpol_internal.h
new file mode 100644
index 0000000..9b51e18
--- /dev/null
+++ b/libqpol/src/qpol_internal.h
@@ -0,0 +1,122 @@
+/**
+ * @file
+ * Defines common debug symbols and the internal policy structure.
+ *
+ * @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
+ */
+
+#ifndef QPOL_INTERNAL_H
+#define QPOL_INTERNAL_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <sepol/handle.h>
+#include <qpol/policy.h>
+#include <stdio.h>
+
+#define STATUS_SUCCESS 0
+#define STATUS_ERR -1
+#define STATUS_NODATA 1
+
+#define QPOL_MSG_ERR 1
+#define QPOL_MSG_WARN 2
+#define QPOL_MSG_INFO 3
+
+ struct qpol_extended_image;
+ struct qpol_policy;
+
+ struct qpol_module
+ {
+ char *name;
+ char *path;
+ char *version;
+ int type;
+ struct sepol_policydb *p;
+ int enabled;
+ struct qpol_policy *parent;
+ };
+
+ struct qpol_policy
+ {
+ struct sepol_policydb *p;
+ struct sepol_handle *sh;
+ qpol_callback_fn_t fn;
+ void *varg;
+ int options;
+ int type;
+ int modified;
+ struct qpol_extended_image *ext;
+ struct qpol_module **modules;
+ size_t num_modules;
+ char *file_data;
+ size_t file_data_sz;
+ int file_data_type;
+ };
+/* qpol_policy_t.file_data_type will be one of the following to denote
+ * the proper method of destroying the data:
+ * _BIN if policy is from a binary source (modular or kernel) destroy is a no-op
+ * _MMAP if policy is from a file and destroy should call munmap
+ * _MEM if policy is from open_from_memory and destroy should call free */
+#define QPOL_POLICY_FILE_DATA_TYPE_BIN 0
+#define QPOL_POLICY_FILE_DATA_TYPE_MMAP 1
+#define QPOL_POLICY_FILE_DATA_TYPE_MEM 2
+
+/**
+ * Create an extended image for a policy. This function modifies the policydb
+ * by adding additional records and information about attributes, initial sids
+ * and other components not normally written to a binary policy file. Subsequent
+ * calls to this function have no effect.
+ * @param policy The policy for which the extended image should be created.
+ * @return Returns 0 on success and < 0 on failure. If the call fails,
+ * errno will be set; the state of the policy is not guaranteed to be stable
+ * if this call fails.
+ */
+ int policy_extend(qpol_policy_t * policy);
+
+ extern void qpol_handle_msg(const qpol_policy_t * policy, int level, const char *fmt, ...);
+ int qpol_is_file_binpol(FILE * fp);
+ int qpol_is_file_mod_pkg(FILE * fp);
+/**
+ * Returns the version number of the binary policy. Note that this
+ * will rewind the file pointer.
+ *
+ * @return Non-negative policy version, or -1 general error for, -2
+ * wrong magic number for file, or -3 problem reading file.
+ */
+ int qpol_binpol_version(FILE * fp);
+
+/**
+ * Returns true if the file is a module package.
+ * @return Returns 1 for module packages, 0 otherwise.
+ */
+ int qpol_is_data_mod_pkg(char * data);
+
+#define ERR(policy, format, ...) qpol_handle_msg(policy, QPOL_MSG_ERR, format, __VA_ARGS__)
+#define WARN(policy, format, ...) qpol_handle_msg(policy, QPOL_MSG_WARN, format, __VA_ARGS__)
+#define INFO(policy, format, ...) qpol_handle_msg(policy, QPOL_MSG_INFO, format, __VA_ARGS__)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* QPOL_INTERNAL_H */
diff --git a/libqpol/src/queue.c b/libqpol/src/queue.c
new file mode 100644
index 0000000..18667d5
--- /dev/null
+++ b/libqpol/src/queue.c
@@ -0,0 +1,183 @@
+/**
+ * @file
+ *
+ * This file is a copy of queue.c from NSA's CVS repository.
+ *
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ */
+
+/* FLASK */
+
+/*
+ * Implementation of the double-ended queue type.
+ */
+
+#include <stdlib.h>
+#include "queue.h"
+
+queue_t queue_create(void)
+{
+ queue_t q;
+
+ q = (queue_t) malloc(sizeof(struct queue_info));
+ if (q == NULL)
+ return NULL;
+
+ q->head = q->tail = NULL;
+
+ return q;
+}
+
+int queue_insert(queue_t q, queue_element_t e)
+{
+ queue_node_ptr_t newnode;
+
+ if (!q)
+ return -1;
+
+ newnode = (queue_node_ptr_t) malloc(sizeof(struct queue_node));
+ if (newnode == NULL)
+ return -1;
+
+ newnode->element = e;
+ newnode->next = NULL;
+
+ if (q->head == NULL) {
+ q->head = q->tail = newnode;
+ } else {
+ q->tail->next = newnode;
+ q->tail = newnode;
+ }
+
+ return 0;
+}
+
+int queue_push(queue_t q, queue_element_t e)
+{
+ queue_node_ptr_t newnode;
+
+ if (!q)
+ return -1;
+
+ newnode = (queue_node_ptr_t) malloc(sizeof(struct queue_node));
+ if (newnode == NULL)
+ return -1;
+
+ newnode->element = e;
+ newnode->next = NULL;
+
+ if (q->head == NULL) {
+ q->head = q->tail = newnode;
+ } else {
+ newnode->next = q->head;
+ q->head = newnode;
+ }
+
+ return 0;
+}
+
+queue_element_t queue_remove(queue_t q)
+{
+ queue_node_ptr_t node;
+ queue_element_t e;
+
+ if (!q)
+ return NULL;
+
+ if (q->head == NULL)
+ return NULL;
+
+ node = q->head;
+ q->head = q->head->next;
+ if (q->head == NULL)
+ q->tail = NULL;
+
+ e = node->element;
+ free(node);
+
+ return e;
+}
+
+queue_element_t queue_head(queue_t q)
+{
+ if (!q)
+ return NULL;
+
+ if (q->head == NULL)
+ return NULL;
+
+ return q->head->element;
+}
+
+void queue_destroy(queue_t q)
+{
+ queue_node_ptr_t p, temp;
+
+ if (!q)
+ return;
+
+ p = q->head;
+ while (p != NULL) {
+ temp = p;
+ p = p->next;
+ free(temp);
+ }
+
+ free(q);
+}
+
+int queue_map(queue_t q, int (*f) (queue_element_t, void *), void *vp)
+{
+ queue_node_ptr_t p;
+ int ret;
+
+ if (!q)
+ return 0;
+
+ p = q->head;
+ while (p != NULL) {
+ ret = f(p->element, vp);
+ if (ret)
+ return ret;
+ p = p->next;
+ }
+ return 0;
+}
+
+void queue_map_remove_on_error(queue_t q, int (*f) (queue_element_t, void *), void (*g) (queue_element_t, void *), void *vp)
+{
+ queue_node_ptr_t p, last, temp;
+ int ret;
+
+ if (!q)
+ return;
+
+ last = NULL;
+ p = q->head;
+ while (p != NULL) {
+ ret = f(p->element, vp);
+ if (ret) {
+ if (last) {
+ last->next = p->next;
+ if (last->next == NULL)
+ q->tail = last;
+ } else {
+ q->head = p->next;
+ if (q->head == NULL)
+ q->tail = NULL;
+ }
+
+ temp = p;
+ p = p->next;
+ g(temp->element, vp);
+ free(temp);
+ } else {
+ last = p;
+ p = p->next;
+ }
+ }
+
+ return;
+}
+
+/* FLASK */
diff --git a/libqpol/src/queue.h b/libqpol/src/queue.h
new file mode 100644
index 0000000..bca304b
--- /dev/null
+++ b/libqpol/src/queue.h
@@ -0,0 +1,67 @@
+/**
+ * @file
+ *
+ * This file is a copy of queue.h from NSA's CVS repository.
+ *
+ * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ */
+
+/* FLASK */
+
+/*
+ * A double-ended queue is a singly linked list of
+ * elements of arbitrary type that may be accessed
+ * at either end.
+ */
+
+#ifndef _QUEUE_H_
+#define _QUEUE_H_
+
+typedef void *queue_element_t;
+
+typedef struct queue_node *queue_node_ptr_t;
+
+typedef struct queue_node
+{
+ queue_element_t element;
+ queue_node_ptr_t next;
+} queue_node_t;
+
+typedef struct queue_info
+{
+ queue_node_ptr_t head;
+ queue_node_ptr_t tail;
+} queue_info_t;
+
+typedef queue_info_t *queue_t;
+
+queue_t queue_create(void);
+int queue_insert(queue_t, queue_element_t);
+int queue_push(queue_t, queue_element_t);
+queue_element_t queue_remove(queue_t);
+queue_element_t queue_head(queue_t);
+void queue_destroy(queue_t);
+
+/*
+ Applies the specified function f to each element in the
+ specified queue.
+
+ In addition to passing the element to f, queue_map
+ passes the specified void* pointer to f on each invocation.
+
+ If f returns a non-zero status, then queue_map will cease
+ iterating through the hash table and will propagate the error
+ return to its caller.
+ */
+int queue_map(queue_t, int (*f) (queue_element_t, void *), void *);
+
+/*
+ Same as queue_map, except that if f returns a non-zero status,
+ then the element will be removed from the queue and the g
+ function will be applied to the element.
+ */
+void queue_map_remove_on_error(queue_t, int (*f) (queue_element_t, void *), void (*g) (queue_element_t, void *), void *);
+
+#endif
+
+/* FLASK */
diff --git a/libqpol/src/rbacrule_query.c b/libqpol/src/rbacrule_query.c
new file mode 100644
index 0000000..7f84459
--- /dev/null
+++ b/libqpol/src/rbacrule_query.c
@@ -0,0 +1,358 @@
+/**
+ * @file
+ * Defines public interface for iterating over RBAC rules.
+ *
+ * @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
+ */
+
+#include <qpol/iterator.h>
+#include <qpol/policy.h>
+#include <qpol/rbacrule_query.h>
+#include <stdlib.h>
+#include "iterator_internal.h"
+#include "qpol_internal.h"
+#include <sepol/policydb/policydb.h>
+
+typedef struct role_allow_state
+{
+ role_allow_t *head;
+ role_allow_t *cur;
+} role_allow_state_t;
+
+static int role_allow_state_end(const qpol_iterator_t * iter)
+{
+ role_allow_state_t *ras = NULL;
+
+ if (!iter || !(ras = qpol_iterator_state(iter))) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ return ras->cur ? 0 : 1;
+}
+
+static void *role_allow_state_get_cur(const qpol_iterator_t * iter)
+{
+ role_allow_state_t *ras = NULL;
+ const policydb_t *db = NULL;
+
+ if (!iter || !(ras = qpol_iterator_state(iter)) || !(db = qpol_iterator_policy(iter)) || role_allow_state_end(iter)) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ return ras->cur;
+}
+
+static int role_allow_state_next(qpol_iterator_t * iter)
+{
+ role_allow_state_t *ras = NULL;
+ const policydb_t *db = NULL;
+
+ if (!iter || !(ras = qpol_iterator_state(iter)) || !(db = qpol_iterator_policy(iter))) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ if (role_allow_state_end(iter)) {
+ errno = ERANGE;
+ return STATUS_ERR;
+ }
+
+ ras->cur = ras->cur->next;
+
+ return STATUS_SUCCESS;
+}
+
+static size_t role_allow_state_size(const qpol_iterator_t * iter)
+{
+ role_allow_state_t *ras = NULL;
+ const policydb_t *db = NULL;
+ role_allow_t *tmp = NULL;
+ size_t count = 0;
+
+ if (!iter || !(ras = qpol_iterator_state(iter)) || !(db = qpol_iterator_policy(iter))) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ for (tmp = ras->head; tmp; tmp = tmp->next)
+ count++;
+
+ return count;
+}
+
+int qpol_policy_get_role_allow_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter)
+{
+ policydb_t *db = NULL;
+ role_allow_state_t *ras = NULL;
+ int error = 0;
+
+ if (iter)
+ *iter = NULL;
+
+ if (!policy || !iter) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+
+ ras = calloc(1, sizeof(role_allow_state_t));
+ if (!ras) {
+ /* errno set by calloc */
+ ERR(policy, "%s", strerror(errno));
+ return STATUS_ERR;
+ }
+ ras->head = ras->cur = db->role_allow;
+
+ if (qpol_iterator_create
+ (policy, (void *)ras, role_allow_state_get_cur, role_allow_state_next, role_allow_state_end, role_allow_state_size,
+ free, iter)) {
+ error = errno;
+ free(ras);
+ errno = error;
+ return STATUS_ERR;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_role_allow_get_source_role(const qpol_policy_t * policy, const qpol_role_allow_t * rule, const qpol_role_t ** source)
+{
+ policydb_t *db = NULL;
+ role_allow_t *ra = NULL;
+
+ if (source) {
+ *source = NULL;
+ }
+
+ if (!policy || !rule || !source) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+ ra = (role_allow_t *) rule;
+
+ *source = (qpol_role_t *) db->role_val_to_struct[ra->role - 1];
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_role_allow_get_target_role(const qpol_policy_t * policy, const qpol_role_allow_t * rule, const qpol_role_t ** target)
+{
+ policydb_t *db = NULL;
+ role_allow_t *ra = NULL;
+
+ if (target) {
+ *target = NULL;
+ }
+
+ if (!policy || !rule || !target) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+ ra = (role_allow_t *) rule;
+
+ *target = (qpol_role_t *) db->role_val_to_struct[ra->new_role - 1];
+
+ return STATUS_SUCCESS;
+}
+
+typedef struct role_trans_state
+{
+ role_trans_t *head;
+ role_trans_t *cur;
+} role_trans_state_t;
+
+static int role_trans_state_end(const qpol_iterator_t * iter)
+{
+ role_trans_state_t *rts = NULL;
+
+ if (!iter || !(rts = qpol_iterator_state(iter))) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ return rts->cur ? 0 : 1;
+}
+
+static void *role_trans_state_get_cur(const qpol_iterator_t * iter)
+{
+ role_trans_state_t *rts = NULL;
+ const policydb_t *db = NULL;
+
+ if (!iter || !(rts = qpol_iterator_state(iter)) || !(db = qpol_iterator_policy(iter)) || role_trans_state_end(iter)) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ return rts->cur;
+}
+
+static int role_trans_state_next(qpol_iterator_t * iter)
+{
+ role_trans_state_t *rts = NULL;
+ const policydb_t *db = NULL;
+
+ if (!iter || !(rts = qpol_iterator_state(iter)) || !(db = qpol_iterator_policy(iter))) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ if (role_trans_state_end(iter)) {
+ errno = ERANGE;
+ return STATUS_ERR;
+ }
+
+ rts->cur = rts->cur->next;
+
+ return STATUS_SUCCESS;
+}
+
+static size_t role_trans_state_size(const qpol_iterator_t * iter)
+{
+ role_trans_state_t *rts = NULL;
+ const policydb_t *db = NULL;
+ role_trans_t *tmp = NULL;
+ size_t count = 0;
+
+ if (!iter || !(rts = qpol_iterator_state(iter)) || !(db = qpol_iterator_policy(iter))) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ for (tmp = rts->head; tmp; tmp = tmp->next)
+ count++;
+
+ return count;
+}
+
+int qpol_policy_get_role_trans_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter)
+{
+ policydb_t *db = NULL;
+ role_trans_state_t *rts = NULL;
+ int error = 0;
+
+ if (iter)
+ *iter = NULL;
+
+ if (!policy || !iter) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+
+ rts = calloc(1, sizeof(role_trans_state_t));
+ if (!rts) {
+ /* errno set by calloc */
+ ERR(policy, "%s", strerror(errno));
+ return STATUS_ERR;
+ }
+ rts->head = rts->cur = db->role_tr;
+
+ if (qpol_iterator_create
+ (policy, (void *)rts, role_trans_state_get_cur, role_trans_state_next, role_trans_state_end, role_trans_state_size,
+ free, iter)) {
+ error = errno;
+ free(rts);
+ errno = error;
+ return STATUS_ERR;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_role_trans_get_source_role(const qpol_policy_t * policy, const qpol_role_trans_t * rule, const qpol_role_t ** source)
+{
+ policydb_t *db = NULL;
+ role_trans_t *rt = NULL;
+
+ if (source) {
+ *source = NULL;
+ }
+
+ if (!policy || !rule || !source) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+ rt = (role_trans_t *) rule;
+
+ *source = (qpol_role_t *) db->role_val_to_struct[rt->role - 1];
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_role_trans_get_target_type(const qpol_policy_t * policy, const qpol_role_trans_t * rule, const qpol_type_t ** target)
+{
+ policydb_t *db = NULL;
+ role_trans_t *rt = NULL;
+
+ if (target) {
+ *target = NULL;
+ }
+
+ if (!policy || !rule || !target) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+ rt = (role_trans_t *) rule;
+
+ *target = (qpol_type_t *) db->type_val_to_struct[rt->type - 1];
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_role_trans_get_default_role(const qpol_policy_t * policy, const qpol_role_trans_t * rule, const qpol_role_t ** dflt)
+{
+ policydb_t *db = NULL;
+ role_trans_t *rt = NULL;
+
+ if (dflt) {
+ *dflt = NULL;
+ }
+
+ if (!policy || !rule || !dflt) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+ rt = (role_trans_t *) rule;
+
+ *dflt = (qpol_role_t *) db->role_val_to_struct[rt->new_role - 1];
+
+ return STATUS_SUCCESS;
+}
diff --git a/libqpol/src/role_query.c b/libqpol/src/role_query.c
new file mode 100644
index 0000000..daa4c06
--- /dev/null
+++ b/libqpol/src/role_query.c
@@ -0,0 +1,238 @@
+/**
+ * @file
+ * Implementation of the interface for searching and iterating over roles.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @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
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <qpol/iterator.h>
+#include <qpol/policy.h>
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/expand.h>
+#include "iterator_internal.h"
+#include <qpol/role_query.h>
+#include <qpol/type_query.h>
+#include "qpol_internal.h"
+
+int qpol_policy_get_role_by_name(const qpol_policy_t * policy, const char *name, const qpol_role_t ** datum)
+{
+ hashtab_datum_t internal_datum;
+ policydb_t *db;
+
+ if (policy == NULL || name == NULL || datum == NULL) {
+ if (datum != NULL)
+ *datum = NULL;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+ internal_datum = hashtab_search(db->p_roles.table, (const hashtab_key_t)name);
+ if (internal_datum == NULL) {
+ *datum = NULL;
+ ERR(policy, "could not find datum for role %s", name);
+ errno = ENOENT;
+ return STATUS_ERR;
+ }
+ *datum = (qpol_role_t *) internal_datum;
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_policy_get_role_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter)
+{
+ policydb_t *db;
+ int error = 0;
+ hash_state_t *hs = NULL;
+
+ if (policy == NULL || iter == NULL) {
+ if (iter != NULL)
+ *iter = NULL;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+
+ hs = calloc(1, sizeof(hash_state_t));
+ if (hs == NULL) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = error;
+ return STATUS_ERR;
+ }
+ hs->table = &db->p_roles.table;
+ hs->node = (*(hs->table))->htable[0];
+
+ if (qpol_iterator_create(policy, (void *)hs, hash_state_get_cur,
+ hash_state_next, hash_state_end, hash_state_size, free, iter)) {
+ free(hs);
+ return STATUS_ERR;
+ }
+
+ if (hs->node == NULL)
+ hash_state_next(*iter);
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_role_get_value(const qpol_policy_t * policy, const qpol_role_t * datum, uint32_t * value)
+{
+ role_datum_t *internal_datum = NULL;
+
+ if (policy == NULL || datum == NULL || value == NULL) {
+ if (value != NULL)
+ *value = 0;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_datum = (role_datum_t *) datum;
+ *value = internal_datum->s.value;
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_role_get_dominate_iter(const qpol_policy_t * policy, const qpol_role_t * datum, qpol_iterator_t ** dominates)
+{
+ role_datum_t *internal_datum = NULL;
+ policydb_t *db = NULL;
+ int error;
+ ebitmap_state_t *es = NULL;
+
+ if (policy == NULL || datum == NULL || dominates == NULL) {
+ if (dominates != NULL)
+ *dominates = NULL;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_datum = (role_datum_t *) datum;
+ db = &policy->p->p;
+
+ if (!(es = calloc(1, sizeof(ebitmap_state_t)))) {
+ error = errno;
+ ERR(policy, "%s", "unable to create iterator state object");
+ errno = error;
+ return STATUS_ERR;
+ }
+ es->bmap = &internal_datum->dominates;
+
+ if (qpol_iterator_create(policy, (void *)es, ebitmap_state_get_cur_role,
+ ebitmap_state_next, ebitmap_state_end, ebitmap_state_size, free, dominates)) {
+ error = errno;
+ free(es);
+ errno = error;
+ return STATUS_ERR;
+ }
+
+ if (es->bmap->node && !ebitmap_get_bit(es->bmap, es->cur))
+ ebitmap_state_next(*dominates);
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_role_get_type_iter(const qpol_policy_t * policy, const qpol_role_t * datum, qpol_iterator_t ** types)
+{
+ role_datum_t *internal_datum = NULL;
+ policydb_t *db = NULL;
+ ebitmap_t *expanded_set = NULL;
+ int error;
+ ebitmap_state_t *es = NULL;
+
+ if (policy == NULL || datum == NULL || types == NULL) {
+ if (types != NULL)
+ *types = NULL;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_datum = (role_datum_t *) datum;
+ db = &policy->p->p;
+
+ if (!(expanded_set = calloc(1, sizeof(ebitmap_t)))) {
+ error = errno;
+ ERR(policy, "%s", "unable to create bitmap");
+ errno = error;
+ return STATUS_ERR;
+ }
+
+ if (type_set_expand(&internal_datum->types, expanded_set, db, 1)) {
+ ebitmap_destroy(expanded_set);
+ free(expanded_set);
+ ERR(policy, "error reading type set for role %s", db->p_role_val_to_name[internal_datum->s.value - 1]);
+ errno = EIO;
+ return STATUS_ERR;
+ }
+
+ if (!(es = calloc(1, sizeof(ebitmap_state_t)))) {
+ error = errno;
+ ERR(policy, "%s", "unable to create iterator state object");
+ ebitmap_destroy(expanded_set);
+ free(expanded_set);
+ errno = error;
+ return STATUS_ERR;
+ }
+ es->bmap = expanded_set;
+ es->cur = es->bmap->node ? es->bmap->node->startbit : 0;
+
+ if (qpol_iterator_create(policy, (void *)es, ebitmap_state_get_cur_type,
+ ebitmap_state_next, ebitmap_state_end, ebitmap_state_size, ebitmap_state_destroy, types)) {
+ error = errno;
+ ebitmap_state_destroy(es);
+ errno = error;
+ return STATUS_ERR;
+ }
+
+ if (es->bmap->node && !ebitmap_get_bit(es->bmap, es->cur))
+ ebitmap_state_next(*types);
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_role_get_name(const qpol_policy_t * policy, const qpol_role_t * datum, const char **name)
+{
+ role_datum_t *internal_datum = NULL;
+ policydb_t *db = NULL;
+
+ if (policy == NULL || datum == NULL || name == NULL) {
+ if (name != NULL)
+ *name = NULL;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+ internal_datum = (role_datum_t *) datum;
+
+ *name = db->p_role_val_to_name[internal_datum->s.value - 1];
+
+ return STATUS_SUCCESS;
+}
diff --git a/libqpol/src/syn_rule_internal.h b/libqpol/src/syn_rule_internal.h
new file mode 100644
index 0000000..8910913
--- /dev/null
+++ b/libqpol/src/syn_rule_internal.h
@@ -0,0 +1,47 @@
+/**
+ * @file
+ * Protected definition for syntactic rules from the extended
+ * policy image.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @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
+ */
+#ifndef QPOL_SYN_RULE_INTERNAL_H
+#define QPOL_SYN_RULE_INTERNAL_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+ struct qpol_syn_rule
+ {
+ avrule_t *rule;
+ cond_node_t *cond;
+ /** 0 if this rule is unconditional or in a conditional's true branch, 1 if in else */
+ int cond_branch;
+/* char *mod_name; for later use */
+ };
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* QPOL_SYN_RULE_INTERNAL_H */
diff --git a/libqpol/src/syn_rule_query.c b/libqpol/src/syn_rule_query.c
new file mode 100644
index 0000000..3e63204
--- /dev/null
+++ b/libqpol/src/syn_rule_query.c
@@ -0,0 +1,782 @@
+/**
+ * @file
+ * Public interface for querying syntactic rules from the extended
+ * policy image.
+ *
+ * @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
+ */
+
+#include <config.h>
+
+#include <qpol/syn_rule_query.h>
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/util.h>
+#include <sepol/policydb/conditional.h>
+#include "qpol_internal.h"
+#include "iterator_internal.h"
+#include "syn_rule_internal.h"
+#include <errno.h>
+#include <stdlib.h>
+
+typedef struct syn_rule_class_state
+{
+ class_perm_node_t *head;
+ class_perm_node_t *cur;
+} syn_rule_class_state_t;
+
+static int syn_rule_class_state_end(const qpol_iterator_t * iter)
+{
+ syn_rule_class_state_t *srcs = NULL;
+
+ if (!iter || !(srcs = (syn_rule_class_state_t *) qpol_iterator_state(iter))) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ if (srcs->cur == NULL)
+ return 1;
+ else
+ return 0;
+}
+
+static void *syn_rule_class_state_get_cur(const qpol_iterator_t * iter)
+{
+ syn_rule_class_state_t *srcs = NULL;
+ const policydb_t *db = NULL;
+
+ if (!iter || !(srcs = (syn_rule_class_state_t *) qpol_iterator_state(iter)) ||
+ !(db = qpol_iterator_policy(iter)) || qpol_iterator_end(iter)) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ return db->class_val_to_struct[srcs->cur->class - 1];
+}
+
+static int syn_rule_class_state_next(qpol_iterator_t * iter)
+{
+ syn_rule_class_state_t *srcs = NULL;
+
+ if (!iter || !(srcs = (syn_rule_class_state_t *) qpol_iterator_state(iter))) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+ if (qpol_iterator_end(iter)) {
+ errno = ERANGE;
+ return STATUS_ERR;
+ }
+
+ srcs->cur = srcs->cur->next;
+
+ return STATUS_SUCCESS;
+}
+
+static size_t syn_rule_class_state_size(const qpol_iterator_t * iter)
+{
+ syn_rule_class_state_t *srcs = NULL;
+ size_t count = 0;
+ class_perm_node_t *cpn = NULL;
+
+ if (!iter || !(srcs = (syn_rule_class_state_t *) qpol_iterator_state(iter))) {
+ errno = EINVAL;
+ return 0;
+ }
+
+ for (cpn = srcs->head; cpn; cpn = cpn->next)
+ count++;
+
+ return count;
+}
+
+typedef struct syn_rule_perm_state
+{
+ char **perm_list;
+ size_t perm_list_sz;
+ size_t cur;
+} syn_rule_perm_state_t;
+
+static int syn_rule_perm_state_end(const qpol_iterator_t * iter)
+{
+ syn_rule_perm_state_t *srps = NULL;
+
+ if (!iter || !(srps = (syn_rule_perm_state_t *) qpol_iterator_state(iter))) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ return (srps->cur >= srps->perm_list_sz ? 1 : 0);
+}
+
+static void *syn_rule_perm_state_get_cur(const qpol_iterator_t * iter)
+{
+ syn_rule_perm_state_t *srps = NULL;
+
+ if (!iter || !(srps = (syn_rule_perm_state_t *) qpol_iterator_state(iter)) || qpol_iterator_end(iter)) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ return srps->perm_list[srps->cur];
+}
+
+static int syn_rule_perm_state_next(qpol_iterator_t * iter)
+{
+ syn_rule_perm_state_t *srps = NULL;
+
+ if (!iter || !(srps = (syn_rule_perm_state_t *) qpol_iterator_state(iter))) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+ if (qpol_iterator_end(iter)) {
+ errno = ERANGE;
+ return STATUS_ERR;
+ }
+
+ srps->cur++;
+
+ return STATUS_SUCCESS;
+}
+
+static size_t syn_rule_perm_state_size(const qpol_iterator_t * iter)
+{
+ syn_rule_perm_state_t *srps = NULL;
+
+ if (!iter || !(srps = (syn_rule_perm_state_t *) qpol_iterator_state(iter))) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ return srps->perm_list_sz;
+}
+
+static void syn_rule_perm_state_free(void *state)
+{
+ size_t i;
+
+ syn_rule_perm_state_t *srps = (syn_rule_perm_state_t *) state;
+
+ if (!srps)
+ return;
+
+ for (i = 0; i < srps->perm_list_sz; i++)
+ free(srps->perm_list[i]);
+ free(srps->perm_list);
+ free(srps);
+}
+
+/***************************** type set functions ****************************/
+
+int qpol_type_set_get_included_types_iter(const qpol_policy_t * policy, const qpol_type_set_t * ts, qpol_iterator_t ** iter)
+{
+ type_set_t *internal_ts = NULL;
+ ebitmap_state_t *es = NULL;
+ int error = 0;
+
+ if (iter)
+ *iter = NULL;
+
+ if (!policy || !ts || !iter) {
+ ERR(policy, "%s", strerror(EINVAL));
+ error = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_ts = (type_set_t *) ts;
+
+ es = calloc(1, sizeof(ebitmap_state_t));
+ if (!es) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ errno = error;
+ return STATUS_ERR;
+ }
+
+ es->bmap = &(internal_ts->types);
+ es->cur = es->bmap->node ? es->bmap->node->startbit : 0;
+
+ if (qpol_iterator_create(policy, es, ebitmap_state_get_cur_type,
+ ebitmap_state_next, ebitmap_state_end, ebitmap_state_size, free, iter)) {
+ free(es);
+ return STATUS_ERR;
+ }
+
+ if (es->bmap->node && !ebitmap_get_bit(es->bmap, es->cur))
+ ebitmap_state_next(*iter);
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_type_set_get_subtracted_types_iter(const qpol_policy_t * policy, const qpol_type_set_t * ts, qpol_iterator_t ** iter)
+{
+ type_set_t *internal_ts = NULL;
+ ebitmap_state_t *es = NULL;
+ int error = 0;
+
+ if (iter)
+ *iter = NULL;
+
+ if (!policy || !ts || !iter) {
+ ERR(policy, "%s", strerror(EINVAL));
+ error = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_ts = (type_set_t *) ts;
+
+ es = calloc(1, sizeof(ebitmap_state_t));
+ if (!es) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ errno = error;
+ return STATUS_ERR;
+ }
+
+ es->bmap = &(internal_ts->negset);
+ es->cur = es->bmap->node ? es->bmap->node->startbit : 0;
+
+ if (qpol_iterator_create(policy, es, ebitmap_state_get_cur_type,
+ ebitmap_state_next, ebitmap_state_end, ebitmap_state_size, free, iter)) {
+ free(es);
+ return STATUS_ERR;
+ }
+
+ if (es->bmap->node && !ebitmap_get_bit(es->bmap, es->cur))
+ ebitmap_state_next(*iter);
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_type_set_get_is_star(const qpol_policy_t * policy, const qpol_type_set_t * ts, uint32_t * is_star)
+{
+ type_set_t *internal_ts = NULL;
+
+ if (is_star)
+ *is_star = 0;
+
+ if (!policy || !ts || !is_star) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_ts = (type_set_t *) ts;
+
+ if (internal_ts->flags == TYPE_STAR)
+ *is_star = 1;
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_type_set_get_is_comp(const qpol_policy_t * policy, const qpol_type_set_t * ts, uint32_t * is_comp)
+{
+ type_set_t *internal_ts = NULL;
+
+ if (is_comp)
+ *is_comp = 0;
+
+ if (!policy || !ts || !is_comp) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_ts = (type_set_t *) ts;
+
+ if (internal_ts->flags == TYPE_COMP)
+ *is_comp = 1;
+
+ return STATUS_SUCCESS;
+}
+
+/***************************** syn_avule functions ****************************/
+
+int qpol_syn_avrule_get_rule_type(const qpol_policy_t * policy, const qpol_syn_avrule_t * rule, uint32_t * rule_type)
+{
+ avrule_t *internal_rule = NULL;
+
+ if (rule_type)
+ *rule_type = 0;
+
+ if (!policy || !rule || !rule_type) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_rule = ((struct qpol_syn_rule *)rule)->rule;
+
+ if (internal_rule->specified == AVRULE_DONTAUDIT)
+ *rule_type = QPOL_RULE_DONTAUDIT;
+ else
+ *rule_type = internal_rule->specified;
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_syn_avrule_get_source_type_set(const qpol_policy_t * policy, const qpol_syn_avrule_t * rule,
+ const qpol_type_set_t ** source_set)
+{
+ avrule_t *internal_rule = NULL;
+
+ if (source_set)
+ *source_set = NULL;
+
+ if (!policy || !rule || !source_set) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_rule = ((struct qpol_syn_rule *)rule)->rule;
+
+ *source_set = (qpol_type_set_t *) (&internal_rule->stypes);
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_syn_avrule_get_target_type_set(const qpol_policy_t * policy, const qpol_syn_avrule_t * rule,
+ const qpol_type_set_t ** target_set)
+{
+ avrule_t *internal_rule = NULL;
+
+ if (target_set)
+ *target_set = NULL;
+
+ if (!policy || !rule || !target_set) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_rule = ((struct qpol_syn_rule *)rule)->rule;
+
+ *target_set = (qpol_type_set_t *) (&internal_rule->ttypes);
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_syn_avrule_get_is_target_self(const qpol_policy_t * policy, const qpol_syn_avrule_t * rule, uint32_t * is_self)
+{
+ avrule_t *internal_rule = NULL;
+
+ if (is_self)
+ *is_self = 0;
+
+ if (!policy || !rule || !is_self) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_rule = ((struct qpol_syn_rule *)rule)->rule;
+
+ if (internal_rule->flags & RULE_SELF)
+ *is_self = 1;
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_syn_avrule_get_class_iter(const qpol_policy_t * policy, const qpol_syn_avrule_t * rule, qpol_iterator_t ** classes)
+{
+ syn_rule_class_state_t *srcs = NULL;
+ avrule_t *internal_rule = NULL;
+ int error = 0;
+
+ if (classes)
+ *classes = NULL;
+
+ if (!policy || !rule || !classes) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ if (!(srcs = calloc(1, sizeof(syn_rule_class_state_t)))) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ errno = error;
+ return STATUS_ERR;
+ }
+
+ internal_rule = ((struct qpol_syn_rule *)rule)->rule;
+ srcs->head = srcs->cur = internal_rule->perms;
+
+ if (qpol_iterator_create(policy, (void *)srcs,
+ syn_rule_class_state_get_cur, syn_rule_class_state_next,
+ syn_rule_class_state_end, syn_rule_class_state_size, free, classes)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ free(srcs);
+ errno = error;
+ return STATUS_ERR;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_syn_avrule_get_perm_iter(const qpol_policy_t * policy, const qpol_syn_avrule_t * rule, qpol_iterator_t ** perms)
+{
+ avrule_t *internal_rule = NULL;
+ policydb_t *db = NULL;
+ char **perm_list, *tmp = NULL, **tmp_copy = NULL;
+ class_perm_node_t *node = NULL;
+ size_t node_num = 0, i, cur, perm_list_sz = 0;
+ int error = 0;
+ syn_rule_perm_state_t *srps = NULL;
+
+ if (perms)
+ *perms = NULL;
+
+ if (!policy || !rule || !perms) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+ internal_rule = ((struct qpol_syn_rule *)rule)->rule;
+ for (node = internal_rule->perms; node; node = node->next)
+ node_num++;
+
+ /* for now allocate space for maximum number of unique perms */
+ perm_list = calloc(node_num * 32, sizeof(char *));
+ if (!perm_list) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ errno = error;
+ return STATUS_ERR;
+ }
+
+ for (node = internal_rule->perms; node; node = node->next) {
+ for (i = 0; i < db->class_val_to_struct[node->class - 1]->permissions.nprim; i++) {
+ if (!(node->data & (1 << i)))
+ continue;
+ tmp = sepol_av_to_string(db, node->class, (sepol_access_vector_t) (1 << i));
+ if (tmp) {
+ tmp++; /* remove prepended space */
+ for (cur = 0; cur < perm_list_sz; cur++)
+ if (!strcmp(tmp, perm_list[cur]))
+ break;
+ if (cur < perm_list_sz)
+ continue;
+ perm_list[perm_list_sz] = strdup(tmp);
+ if (!(perm_list[perm_list_sz])) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto err;
+ }
+ perm_list_sz++;
+ } else {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto err;
+ }
+ }
+ }
+
+ /* shrink to actual needed size */
+ tmp_copy = realloc(perm_list, perm_list_sz * sizeof(char *));
+ if (!tmp_copy) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto err;
+ }
+ perm_list = tmp_copy;
+
+ srps = calloc(1, sizeof(syn_rule_perm_state_t));
+ if (!srps) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto err;
+ }
+ srps->perm_list = perm_list;
+ srps->perm_list_sz = perm_list_sz;
+ srps->cur = 0;
+
+ if (qpol_iterator_create(policy, (void *)srps,
+ syn_rule_perm_state_get_cur, syn_rule_perm_state_next,
+ syn_rule_perm_state_end, syn_rule_perm_state_size, syn_rule_perm_state_free, perms)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto err;
+ }
+
+ return STATUS_SUCCESS;
+
+ err:
+ for (i = 0; i < perm_list_sz; i++)
+ free(perm_list[i]);
+ free(perm_list);
+ errno = error;
+ return STATUS_ERR;
+}
+
+int qpol_syn_avrule_get_lineno(const qpol_policy_t * policy, const qpol_syn_avrule_t * rule, unsigned long *lineno)
+{
+ avrule_t *internal_rule = NULL;
+
+ if (lineno)
+ *lineno = 0;
+
+ if (!policy || !rule || !lineno) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_rule = ((struct qpol_syn_rule *)rule)->rule;
+
+ *lineno = internal_rule->line;
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_syn_avrule_get_cond(const qpol_policy_t * policy, const qpol_syn_avrule_t * rule, const qpol_cond_t ** cond)
+{
+ if (cond)
+ *cond = NULL;
+
+ if (!policy || !rule || !cond) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ *cond = (qpol_cond_t *) ((struct qpol_syn_rule *)rule)->cond;
+ return STATUS_SUCCESS;
+}
+
+int qpol_syn_avrule_get_is_enabled(const qpol_policy_t * policy, const qpol_syn_avrule_t * rule, uint32_t * is_enabled)
+{
+ int truth;
+ if (is_enabled)
+ *is_enabled = 0;
+
+ if (!policy || !rule || !is_enabled) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ if (!((struct qpol_syn_rule *)rule)->cond)
+ *is_enabled = 1;
+ else {
+ truth = cond_evaluate_expr(&policy->p->p, ((struct qpol_syn_rule *)rule)->cond->expr);
+ if (truth < 0) {
+ ERR(policy, "%s", strerror(ERANGE));
+ errno = ERANGE;
+ return STATUS_ERR;
+ }
+ if (!((struct qpol_syn_rule *)rule)->cond_branch)
+ *is_enabled = truth;
+ else
+ *is_enabled = truth ? 0 : 1;
+ }
+ return STATUS_SUCCESS;
+}
+
+/***************************** syn_terule functions ****************************/
+
+int qpol_syn_terule_get_rule_type(const qpol_policy_t * policy, const qpol_syn_terule_t * rule, uint32_t * rule_type)
+{
+ avrule_t *internal_rule = NULL;
+
+ if (rule_type)
+ *rule_type = 0;
+
+ if (!policy || !rule || !rule_type) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_rule = ((struct qpol_syn_rule *)rule)->rule;
+
+ *rule_type = internal_rule->specified;
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_syn_terule_get_source_type_set(const qpol_policy_t * policy, const qpol_syn_terule_t * rule,
+ const qpol_type_set_t ** source_set)
+{
+ avrule_t *internal_rule = NULL;
+
+ if (source_set)
+ *source_set = NULL;
+
+ if (!policy || !rule || !source_set) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_rule = ((struct qpol_syn_rule *)rule)->rule;
+
+ *source_set = (qpol_type_set_t *) (&internal_rule->stypes);
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_syn_terule_get_target_type_set(const qpol_policy_t * policy, const qpol_syn_terule_t * rule,
+ const qpol_type_set_t ** target_set)
+{
+ avrule_t *internal_rule = NULL;
+
+ if (target_set)
+ *target_set = NULL;
+
+ if (!policy || !rule || !target_set) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_rule = ((struct qpol_syn_rule *)rule)->rule;
+
+ *target_set = (qpol_type_set_t *) (&internal_rule->ttypes);
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_syn_terule_get_class_iter(const qpol_policy_t * policy, const qpol_syn_terule_t * rule, qpol_iterator_t ** classes)
+{
+ syn_rule_class_state_t *srcs = NULL;
+ avrule_t *internal_rule = NULL;
+ int error = 0;
+
+ if (classes)
+ *classes = NULL;
+
+ if (!policy || !rule || !classes) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ if (!(srcs = calloc(1, sizeof(syn_rule_class_state_t)))) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ errno = error;
+ return STATUS_ERR;
+ }
+
+ internal_rule = ((struct qpol_syn_rule *)rule)->rule;
+ srcs->head = srcs->cur = internal_rule->perms;
+
+ if (qpol_iterator_create(policy, (void *)srcs,
+ syn_rule_class_state_get_cur, syn_rule_class_state_next,
+ syn_rule_class_state_end, syn_rule_class_state_size, free, classes)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ free(srcs);
+ errno = error;
+ return STATUS_ERR;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_syn_terule_get_default_type(const qpol_policy_t * policy, const qpol_syn_terule_t * rule, const qpol_type_t ** dflt)
+{
+ avrule_t *internal_rule = NULL;
+ policydb_t *db = NULL;
+
+ if (dflt)
+ *dflt = 0;
+
+ if (!policy || !rule || !dflt) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_rule = ((struct qpol_syn_rule *)rule)->rule;
+ db = &policy->p->p;
+
+ /* since it is required that default be the same for all classes just return the first */
+ *dflt = (qpol_type_t *) (db->type_val_to_struct[internal_rule->perms->data - 1]);
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_syn_terule_get_lineno(const qpol_policy_t * policy, const qpol_syn_terule_t * rule, unsigned long *lineno)
+{
+ avrule_t *internal_rule = NULL;
+
+ if (lineno)
+ *lineno = 0;
+
+ if (!policy || !rule || !lineno) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_rule = ((struct qpol_syn_rule *)rule)->rule;
+
+ *lineno = internal_rule->line;
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_syn_terule_get_cond(const qpol_policy_t * policy, const qpol_syn_terule_t * rule, const qpol_cond_t ** cond)
+{
+ if (cond)
+ *cond = NULL;
+
+ if (!policy || !rule || !cond) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ *cond = (qpol_cond_t *) ((struct qpol_syn_rule *)rule)->cond;
+ return STATUS_SUCCESS;
+}
+
+int qpol_syn_terule_get_is_enabled(const qpol_policy_t * policy, const qpol_syn_terule_t * rule, uint32_t * is_enabled)
+{
+ int truth;
+ if (is_enabled)
+ *is_enabled = 0;
+
+ if (!policy || !rule || !is_enabled) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ if (!((struct qpol_syn_rule *)rule)->cond)
+ *is_enabled = 1;
+ else {
+ truth = cond_evaluate_expr(&policy->p->p, ((struct qpol_syn_rule *)rule)->cond->expr);
+ if (truth < 0) {
+ ERR(policy, "%s", strerror(ERANGE));
+ errno = ERANGE;
+ return STATUS_ERR;
+ }
+ if (!((struct qpol_syn_rule *)rule)->cond_branch)
+ *is_enabled = truth;
+ else
+ *is_enabled = truth ? 0 : 1;
+ }
+ return STATUS_SUCCESS;
+}
diff --git a/libqpol/src/terule_query.c b/libqpol/src/terule_query.c
new file mode 100644
index 0000000..7973922
--- /dev/null
+++ b/libqpol/src/terule_query.c
@@ -0,0 +1,264 @@
+/**
+ * @file
+ * Implementation for the public interface for searching and iterating over type rules.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @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
+ */
+
+#include "iterator_internal.h"
+#include <qpol/iterator.h>
+#include <qpol/policy.h>
+#include <qpol/terule_query.h>
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/avtab.h>
+#include <sepol/policydb/util.h>
+#include <stdlib.h>
+#include "qpol_internal.h"
+
+int qpol_policy_get_terule_iter(const qpol_policy_t * policy, uint32_t rule_type_mask, qpol_iterator_t ** iter)
+{
+ policydb_t *db;
+ avtab_state_t *state;
+
+ if (iter) {
+ *iter = NULL;
+ }
+ if (policy == NULL || iter == NULL) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+#if 1 // Seems to make sediff/sediffx work better without breaking things
+ if (!qpol_policy_has_capability(policy, QPOL_CAP_RULES_LOADED)) {
+ ERR(policy, "%s", "Cannot get terules: Rules not loaded");
+ errno = ENOTSUP;
+ return STATUS_ERR;
+ }
+#endif
+
+ db = &policy->p->p;
+
+ state = calloc(1, sizeof(avtab_state_t));
+ if (state == NULL) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return STATUS_ERR;
+ }
+ state->ucond_tab = &db->te_avtab;
+ state->cond_tab = &db->te_cond_avtab;
+ state->rule_type_mask = rule_type_mask;
+ state->node = db->te_avtab.htable[0];
+
+ if (qpol_iterator_create
+ (policy, state, avtab_state_get_cur, avtab_state_next, avtab_state_end, avtab_state_size, free, iter)) {
+ free(state);
+ return STATUS_ERR;
+ }
+ if (state->node == NULL || !(state->node->key.specified & state->rule_type_mask)) {
+ avtab_state_next(*iter);
+ }
+ return STATUS_SUCCESS;
+}
+
+int qpol_terule_get_source_type(const qpol_policy_t * policy, const qpol_terule_t * rule, const qpol_type_t ** source)
+{
+ policydb_t *db = NULL;
+ avtab_ptr_t terule = NULL;
+
+ if (source) {
+ *source = NULL;
+ }
+
+ if (!policy || !rule || !source) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+ terule = (avtab_ptr_t) rule;
+
+ *source = (qpol_type_t *) db->type_val_to_struct[terule->key.source_type - 1];
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_terule_get_target_type(const qpol_policy_t * policy, const qpol_terule_t * rule, const qpol_type_t ** target)
+{
+ policydb_t *db = NULL;
+ avtab_ptr_t terule = NULL;
+
+ if (target) {
+ *target = NULL;
+ }
+
+ if (!policy || !rule || !target) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+ terule = (avtab_ptr_t) rule;
+
+ *target = (qpol_type_t *) db->type_val_to_struct[terule->key.target_type - 1];
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_terule_get_object_class(const qpol_policy_t * policy, const qpol_terule_t * rule, const qpol_class_t ** obj_class)
+{
+ policydb_t *db = NULL;
+ avtab_ptr_t terule = NULL;
+
+ if (obj_class) {
+ *obj_class = NULL;
+ }
+
+ if (!policy || !rule || !obj_class) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+ terule = (avtab_ptr_t) rule;
+
+ *obj_class = (qpol_class_t *) db->class_val_to_struct[terule->key.target_class - 1];
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_terule_get_default_type(const qpol_policy_t * policy, const qpol_terule_t * rule, const qpol_type_t ** dflt)
+{
+ policydb_t *db = NULL;
+ avtab_ptr_t terule = NULL;
+
+ if (dflt) {
+ *dflt = NULL;
+ }
+
+ if (!policy || !rule || !dflt) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+ terule = (avtab_ptr_t) rule;
+
+ *dflt = (qpol_type_t *) db->type_val_to_struct[terule->datum.data - 1];
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_terule_get_rule_type(const qpol_policy_t * policy, const qpol_terule_t * rule, uint32_t * rule_type)
+{
+ policydb_t *db = NULL;
+ avtab_ptr_t terule = NULL;
+
+ if (rule_type) {
+ *rule_type = 0;
+ }
+
+ if (!policy || !rule || !rule_type) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+ terule = (avtab_ptr_t) rule;
+
+ *rule_type = (terule->key.specified & (QPOL_RULE_TYPE_TRANS | QPOL_RULE_TYPE_CHANGE | QPOL_RULE_TYPE_MEMBER));
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_terule_get_cond(const qpol_policy_t * policy, const qpol_terule_t * rule, const qpol_cond_t ** cond)
+{
+ avtab_ptr_t terule = NULL;
+
+ if (cond) {
+ *cond = NULL;
+ }
+
+ if (!policy || !rule || !cond) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ terule = (avtab_ptr_t) rule;
+
+ *cond = (qpol_cond_t *) terule->parse_context;
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_terule_get_is_enabled(const qpol_policy_t * policy, const qpol_terule_t * rule, uint32_t * is_enabled)
+{
+ avtab_ptr_t terule = NULL;
+
+ if (is_enabled) {
+ *is_enabled = 0;
+ }
+
+ if (!policy || !rule || !is_enabled) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ terule = (avtab_ptr_t) rule;
+
+ *is_enabled = ((terule->merged & QPOL_COND_RULE_ENABLED) ? 1 : 0);
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_terule_get_which_list(const qpol_policy_t * policy, const qpol_terule_t * rule, uint32_t * which_list)
+{
+ avtab_ptr_t terule = NULL;
+
+ if (which_list) {
+ *which_list = 0;
+ }
+
+ if (!policy || !rule || !which_list) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ terule = (avtab_ptr_t) rule;
+
+ if (!terule->parse_context) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ *which_list = ((terule->merged & QPOL_COND_RULE_LIST) ? 1 : 0);
+
+ return STATUS_SUCCESS;
+}
diff --git a/libqpol/src/type_query.c b/libqpol/src/type_query.c
new file mode 100644
index 0000000..a746180
--- /dev/null
+++ b/libqpol/src/type_query.c
@@ -0,0 +1,468 @@
+/**
+ * @file
+ * Implementation of the interface for searching and iterating over types.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2006-2008 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
+ */
+
+#include <config.h>
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <qpol/iterator.h>
+#include <qpol/policy.h>
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/expand.h>
+#include "iterator_internal.h"
+#include <qpol/type_query.h>
+#include "qpol_internal.h"
+
+int qpol_policy_get_type_by_name(const qpol_policy_t * policy, const char *name, const qpol_type_t ** datum)
+{
+ hashtab_datum_t internal_datum;
+ policydb_t *db;
+
+ if (policy == NULL || name == NULL || datum == NULL) {
+ if (datum != NULL)
+ *datum = NULL;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+ internal_datum = hashtab_search(db->p_types.table, (const hashtab_key_t)name);
+ if (internal_datum == NULL) {
+ *datum = NULL;
+ ERR(policy, "could not find datum for type %s", name);
+ errno = ENOENT;
+ return STATUS_ERR;
+ }
+ *datum = (qpol_type_t *) internal_datum;
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_policy_get_type_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter)
+{
+ policydb_t *db;
+ int error = 0;
+ hash_state_t *hs = NULL;
+
+ if (policy == NULL || iter == NULL) {
+ if (iter != NULL)
+ *iter = NULL;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+
+ hs = calloc(1, sizeof(hash_state_t));
+ if (hs == NULL) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = error;
+ return STATUS_ERR;
+ }
+ hs->table = &db->p_types.table;
+ hs->node = (*(hs->table))->htable[0];
+
+ if (qpol_iterator_create(policy, (void *)hs, hash_state_get_cur,
+ hash_state_next, hash_state_end, hash_state_size, free, iter)) {
+ free(hs);
+ return STATUS_ERR;
+ }
+
+ if (hs->node == NULL)
+ hash_state_next(*iter);
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_type_get_value(const qpol_policy_t * policy, const qpol_type_t * datum, uint32_t * value)
+{
+ type_datum_t *internal_datum;
+
+ if (policy == NULL || datum == NULL || value == NULL) {
+ if (value != NULL)
+ *value = 0;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_datum = (type_datum_t *) datum;
+ if (internal_datum->flavor == TYPE_ALIAS) {
+ /* aliases that came from modules should use the value
+ * referenced to by that alias */
+ *value = internal_datum->primary;
+ } else {
+ *value = internal_datum->s.value;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+/**
+ * Determine if a type_datum_t is an alias or a non-alias (primary
+ * type or an attribute). For aliases declared in base policies, they
+ * will have no primary value and a flavor of TYPE_TYPE. For aliases
+ * declared in modules, they have a flavor of TYPE_ALIAS; their
+ * primary value points to the new /linked/ type's value.
+ *
+ * @param datum Type datum to check.
+ *
+ * @return 1 if the datum is an alias, 0 if not.
+ */
+static int is_type_really_an_alias(const type_datum_t * datum)
+{
+ if (datum->primary == 0 && datum->flavor == TYPE_TYPE) {
+ return 1;
+ }
+ if (datum->flavor == TYPE_ALIAS) {
+ return 1;
+ }
+ return 0;
+}
+
+int qpol_type_get_isalias(const qpol_policy_t * policy, const qpol_type_t * datum, unsigned char *isalias)
+{
+ type_datum_t *internal_datum;
+
+ if (policy == NULL || datum == NULL || isalias == NULL) {
+ if (isalias != NULL)
+ *isalias = 0;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+ internal_datum = (type_datum_t *) datum;
+ *isalias = is_type_really_an_alias(internal_datum);
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_type_get_isattr(const qpol_policy_t * policy, const qpol_type_t * datum, unsigned char *isattr)
+{
+ type_datum_t *internal_datum;
+
+ if (policy == NULL || datum == NULL || isattr == NULL) {
+ if (isattr != NULL)
+ *isattr = 0;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_datum = (type_datum_t *) datum;
+ *isattr = (internal_datum->flavor == TYPE_ATTRIB ? 1 : 0);
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_type_get_ispermissive(const qpol_policy_t * policy, const qpol_type_t * datum, unsigned char *ispermissive)
+{
+ if (policy == NULL || datum == NULL || ispermissive == NULL) {
+ if (ispermissive != NULL)
+ *ispermissive = 0;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+#ifdef HAVE_SEPOL_PERMISSIVE_TYPES
+ /* checking internal_datum->flags for permissive won't work,
+ because the type could be an alias. so instead, look up
+ its value within the permissive map */
+ uint32_t value;
+ if (qpol_type_get_value(policy, datum, &value) < 0) {
+ return STATUS_ERR;
+ }
+ policydb_t *p = &policy->p->p;
+ /* note that unlike other bitmaps, this one does not subtract
+ 1 in the bitmap */
+ *ispermissive = ebitmap_get_bit(&p->permissive_map, value);
+#else
+ *ispermissive = 0;
+#endif
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_type_get_type_iter(const qpol_policy_t * policy, const qpol_type_t * datum, qpol_iterator_t ** types)
+{
+ type_datum_t *internal_datum = NULL;
+ ebitmap_state_t *es = NULL;
+ int error = 0;
+
+ if (types != NULL)
+ *types = NULL;
+
+ if (policy == NULL || datum == NULL || types == NULL) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_datum = (type_datum_t *) datum;
+
+ if (internal_datum->flavor != TYPE_ATTRIB) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_NODATA;
+ }
+
+ es = calloc(1, sizeof(ebitmap_state_t));
+ if (es == NULL) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = error;
+ return STATUS_ERR;
+ }
+
+ es->bmap = &(internal_datum->types);
+ es->cur = es->bmap->node ? es->bmap->node->startbit : 0;
+
+ if (qpol_iterator_create(policy, es, ebitmap_state_get_cur_type,
+ ebitmap_state_next, ebitmap_state_end, ebitmap_state_size, free, types)) {
+ free(es);
+ return STATUS_ERR;
+ }
+
+ if (es->bmap->node && !ebitmap_get_bit(es->bmap, es->cur))
+ ebitmap_state_next(*types);
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_type_get_attr_iter(const qpol_policy_t * policy, const qpol_type_t * datum, qpol_iterator_t ** attrs)
+{
+ type_datum_t *internal_datum = NULL;
+ ebitmap_state_t *es = NULL;
+ int error = 0;
+
+ if (attrs != NULL)
+ *attrs = NULL;
+
+ if (policy == NULL || datum == NULL || attrs == NULL) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_datum = (type_datum_t *) datum;
+
+ if (internal_datum->flavor == TYPE_ATTRIB) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_NODATA;
+ }
+
+ es = calloc(1, sizeof(ebitmap_state_t));
+ if (es == NULL) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = error;
+ return STATUS_ERR;
+ }
+
+ es->bmap = &(internal_datum->types);
+ es->cur = es->bmap->node ? es->bmap->node->startbit : 0;
+
+ if (qpol_iterator_create(policy, es, ebitmap_state_get_cur_type,
+ ebitmap_state_next, ebitmap_state_end, ebitmap_state_size, free, attrs)) {
+ free(es);
+ return STATUS_ERR;
+ }
+
+ if (es->bmap->node && !ebitmap_get_bit(es->bmap, es->cur))
+ ebitmap_state_next(*attrs);
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_type_get_name(const qpol_policy_t * policy, const qpol_type_t * datum, const char **name)
+{
+ type_datum_t *internal_datum = NULL;
+ policydb_t *db = NULL;
+
+ if (policy == NULL || datum == NULL || name == NULL) {
+ if (name != NULL)
+ *name = NULL;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+ internal_datum = (type_datum_t *) datum;
+
+ *name = db->p_type_val_to_name[internal_datum->s.value - 1];
+
+ return STATUS_SUCCESS;
+}
+
+typedef struct type_alias_hash_state
+{
+ unsigned int bucket;
+ hashtab_node_t *node;
+ hashtab_t *table;
+ uint32_t val;
+} type_alias_hash_state_t;
+
+/**
+ * For aliases that came from the base policy, their primary type is
+ * referenced by s.value. For aliases that came from modules, their
+ * primary type is referenced by the primary field.
+ *
+ * @param datum Alias whose primary value to get.
+ *
+ * @return The primary type's identifier.
+ */
+static uint32_t get_alias_primary(const type_datum_t * datum)
+{
+ if (datum->flavor == TYPE_TYPE) {
+ return datum->s.value;
+ } else {
+ return datum->primary;
+ }
+}
+
+static int hash_state_next_type_alias(qpol_iterator_t * iter)
+{
+ type_alias_hash_state_t *hs = NULL;
+ type_datum_t *datum = NULL;
+
+ if (iter == NULL) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+ hs = (type_alias_hash_state_t *) qpol_iterator_state(iter);
+ if (hs == NULL) {
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ if (hs->bucket >= (*(hs->table))->size) {
+ errno = ERANGE;
+ return STATUS_ERR;
+ }
+
+ do {
+ hash_state_next(iter);
+ datum = hs->node ? (type_datum_t *) hs->node->datum : NULL;
+ } while (datum != NULL && (hs->val != get_alias_primary(datum) || !is_type_really_an_alias(datum)));
+
+ return STATUS_SUCCESS;
+}
+
+static void *hash_state_get_cur_alias(const qpol_iterator_t * iter)
+{
+ type_alias_hash_state_t *hs = NULL;
+
+ if (iter == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ hs = (type_alias_hash_state_t *) qpol_iterator_state(iter);
+ if (hs == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ if (hs->bucket >= (*(hs->table))->size) {
+ errno = ERANGE;
+ return NULL;
+ }
+
+ return hs->node->key;
+}
+
+static size_t hash_alias_state_size(const qpol_iterator_t * iter)
+{
+ type_alias_hash_state_t *hs = NULL;
+ type_datum_t *tmp_datum;
+ hashtab_node_t *tmp_node;
+ uint32_t tmp_bucket = 0;
+ size_t count = 0;
+
+ if (iter == NULL || qpol_iterator_state(iter) == NULL) {
+ errno = EINVAL;
+ return 0;
+ }
+
+ hs = (type_alias_hash_state_t *) qpol_iterator_state(iter);
+
+ for (tmp_bucket = 0; tmp_bucket < (*(hs->table))->size; tmp_bucket++) {
+ for (tmp_node = (*(hs->table))->htable[tmp_bucket]; tmp_node; tmp_node = tmp_node->next) {
+ tmp_datum = tmp_node ? tmp_node->datum : NULL;
+ if (tmp_datum) {
+ if (hs->val == get_alias_primary(tmp_datum) && is_type_really_an_alias(tmp_datum)) {
+ count++;
+ }
+ }
+ }
+ }
+ return count;
+}
+
+int qpol_type_get_alias_iter(const qpol_policy_t * policy, const qpol_type_t * datum, qpol_iterator_t ** aliases)
+{
+ type_datum_t *internal_datum = NULL;
+ policydb_t *db = NULL;
+ int error = 0;
+ type_alias_hash_state_t *hs = NULL;
+
+ if (policy == NULL || datum == NULL || aliases == NULL) {
+ if (aliases != NULL)
+ *aliases = NULL;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+ internal_datum = (type_datum_t *) datum;
+
+ hs = calloc(1, sizeof(type_alias_hash_state_t));
+ if (hs == NULL) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = error;
+ return STATUS_ERR;
+ }
+ hs->table = &db->p_types.table;
+ hs->node = (*(hs->table))->htable[0];
+ hs->val = get_alias_primary(internal_datum);
+
+ if (qpol_iterator_create(policy, (void *)hs, hash_state_get_cur_alias,
+ hash_state_next_type_alias, hash_state_end, hash_alias_state_size, free, aliases)) {
+ free(hs);
+ return STATUS_ERR;
+ }
+
+ if (hs->node == NULL || hs->val != get_alias_primary((type_datum_t *) (hs->node->datum)) ||
+ !is_type_really_an_alias((type_datum_t *) hs->node->datum))
+ hash_state_next_type_alias(*aliases);
+
+ return STATUS_SUCCESS;
+}
diff --git a/libqpol/src/user_query.c b/libqpol/src/user_query.c
new file mode 100644
index 0000000..37237d5
--- /dev/null
+++ b/libqpol/src/user_query.c
@@ -0,0 +1,224 @@
+/**
+ * @file
+ * Implementation of the interface for searching and iterating over users.
+ *
+ * @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
+ */
+
+#include <config.h>
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/expand.h>
+
+#include <qpol/iterator.h>
+#include <qpol/mls_query.h>
+#include <qpol/policy.h>
+#include <qpol/role_query.h>
+#include <qpol/user_query.h>
+#include "iterator_internal.h"
+#include "qpol_internal.h"
+
+int qpol_policy_get_user_by_name(const qpol_policy_t * policy, const char *name, const qpol_user_t ** datum)
+{
+ hashtab_datum_t internal_datum;
+ policydb_t *db;
+
+ if (policy == NULL || name == NULL || datum == NULL) {
+ if (datum != NULL)
+ *datum = NULL;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+ internal_datum = hashtab_search(db->p_users.table, (const hashtab_key_t)name);
+ if (internal_datum == NULL) {
+ *datum = NULL;
+ ERR(policy, "could not find datum for user %s", name);
+ errno = ENOENT;
+ return STATUS_ERR;
+ }
+ *datum = (qpol_user_t *) internal_datum;
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_policy_get_user_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter)
+{
+ policydb_t *db;
+ hash_state_t *hs = NULL;
+ int error = 0;
+
+ if (policy == NULL || iter == NULL) {
+ if (iter != NULL)
+ *iter = NULL;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+
+ hs = calloc(1, sizeof(hash_state_t));
+ if (hs == NULL) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = error;
+ return STATUS_ERR;
+ }
+ hs->table = &db->p_users.table;
+ hs->node = (*(hs->table))->htable[0];
+
+ if (qpol_iterator_create(policy, (void *)hs, hash_state_get_cur,
+ hash_state_next, hash_state_end, hash_state_size, free, iter)) {
+ free(hs);
+ return STATUS_ERR;
+ }
+
+ if (hs->node == NULL)
+ hash_state_next(*iter);
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_user_get_value(const qpol_policy_t * policy, const qpol_user_t * datum, uint32_t * value)
+{
+ user_datum_t *internal_datum;
+
+ if (policy == NULL || datum == NULL || value == NULL) {
+ if (value != NULL)
+ *value = 0;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_datum = (user_datum_t *) datum;
+ *value = internal_datum->s.value;
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_user_get_role_iter(const qpol_policy_t * policy, const qpol_user_t * datum, qpol_iterator_t ** roles)
+{
+ user_datum_t *internal_datum = NULL;
+ int error = 0;
+ ebitmap_state_t *es = NULL;
+
+ if (policy == NULL || datum == NULL || roles == NULL) {
+ if (roles != NULL)
+ *roles = NULL;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ internal_datum = (user_datum_t *) datum;
+
+ es = calloc(1, sizeof(ebitmap_state_t));
+ if (es == NULL) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = error;
+ return STATUS_ERR;
+ }
+
+ es->bmap = &(internal_datum->roles.roles);
+ es->cur = es->bmap->node ? es->bmap->node->startbit : 0;
+
+ if (qpol_iterator_create(policy, es, ebitmap_state_get_cur_role,
+ ebitmap_state_next, ebitmap_state_end, ebitmap_state_size, free, roles)) {
+ free(es);
+ return STATUS_ERR;
+ }
+
+ if (es->bmap->node && !ebitmap_get_bit(es->bmap, es->cur))
+ ebitmap_state_next(*roles);
+
+ return STATUS_SUCCESS;
+}
+
+int qpol_user_get_range(const qpol_policy_t * policy, const qpol_user_t * datum, const qpol_mls_range_t ** range)
+{
+ user_datum_t *internal_datum = NULL;
+
+ if (policy == NULL || datum == NULL || range == NULL) {
+ if (range != NULL)
+ *range = NULL;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ if (!qpol_policy_has_capability(policy, QPOL_CAP_MLS)) {
+ *range = NULL;
+ } else {
+ internal_datum = (user_datum_t *) datum;
+ *range = (qpol_mls_range_t *) & internal_datum->exp_range;
+ }
+ return STATUS_SUCCESS;
+}
+
+int qpol_user_get_dfltlevel(const qpol_policy_t * policy, const qpol_user_t * datum, const qpol_mls_level_t ** level)
+{
+ user_datum_t *internal_datum = NULL;
+
+ if (policy == NULL || datum == NULL || level == NULL) {
+ if (level != NULL)
+ *level = NULL;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ if (!qpol_policy_has_capability(policy, QPOL_CAP_MLS)) {
+ *level = NULL;
+ } else {
+ internal_datum = (user_datum_t *) datum;
+ *level = (qpol_mls_level_t *) & internal_datum->exp_dfltlevel;
+ }
+ return STATUS_SUCCESS;
+}
+
+int qpol_user_get_name(const qpol_policy_t * policy, const qpol_user_t * datum, const char **name)
+{
+ user_datum_t *internal_datum = NULL;
+ policydb_t *db = NULL;
+
+ if (policy == NULL || datum == NULL || name == NULL) {
+ if (name != NULL)
+ *name = NULL;
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return STATUS_ERR;
+ }
+
+ db = &policy->p->p;
+ internal_datum = (user_datum_t *) datum;
+
+ *name = db->p_user_val_to_name[internal_datum->s.value - 1];
+
+ return STATUS_SUCCESS;
+}
diff --git a/libqpol/src/util.c b/libqpol/src/util.c
new file mode 100644
index 0000000..7c49876
--- /dev/null
+++ b/libqpol/src/util.c
@@ -0,0 +1,231 @@
+/**
+ * @file
+ *
+ * Implementation of utility functions.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2006-2008 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
+ */
+
+#include <config.h>
+
+#include "qpol_internal.h"
+
+#include <qpol/util.h>
+
+#include <glob.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <selinux/selinux.h>
+
+const char *libqpol_get_version(void)
+{
+ return LIBQPOL_VERSION_STRING;
+}
+
+static int search_policy_source_file(char **path)
+{
+ int error;
+ char *source_path;
+ if (asprintf(&source_path, "%s/src/policy/policy.conf", selinux_policy_root()) < 0) {
+ return -1;
+ }
+ if (access(source_path, R_OK) < 0) {
+ error = errno;
+ free(source_path);
+ errno = error;
+ return 1;
+ }
+ *path = source_path;
+ return 0;
+}
+
+static int get_binpol_version(const char *policy_fname)
+{
+ FILE *policy_fp = NULL;
+ int ret_version, error;
+
+ policy_fp = fopen(policy_fname, "r");
+ if (policy_fp == NULL) {
+ return -1;
+ }
+ if (!qpol_is_file_binpol(policy_fp)) {
+ error = errno;
+ fclose(policy_fp);
+ errno = error;
+ return -1;
+ }
+ ret_version = qpol_binpol_version(policy_fp);
+ fclose(policy_fp);
+ return ret_version;
+}
+
+static int search_policy_binary_file(char **path)
+{
+ const char *binary_path;
+ if ((binary_path = selinux_binary_policy_path()) == NULL) {
+ return -1;
+ }
+
+ int expected_version = -1, latest_version = -1;
+#ifdef LIBSELINUX
+ /* if the system has SELinux enabled, prefer the policy whose
+ name matches the current policy version */
+ if ((expected_version = security_policyvers()) < 0) {
+ return -1;
+ }
+#endif
+
+ glob_t glob_buf;
+ struct stat fs;
+ int rt, error = 0, retval = -1;
+ size_t i;
+ char *pattern = NULL;
+ if (asprintf(&pattern, "%s.*", binary_path) < 0) {
+ return -1;
+ }
+ glob_buf.gl_offs = 1;
+ glob_buf.gl_pathc = 0;
+ rt = glob(pattern, GLOB_DOOFFS, NULL, &glob_buf);
+ if (rt != 0 && rt != GLOB_NOMATCH) {
+ errno = EIO;
+ return -1;
+ }
+
+ for (i = 0; i < glob_buf.gl_pathc; i++) {
+ char *p = glob_buf.gl_pathv[i + glob_buf.gl_offs];
+ if (stat(p, &fs) != 0) {
+ error = errno;
+ goto cleanup;
+ }
+ if (S_ISDIR(fs.st_mode))
+ continue;
+
+ if ((rt = get_binpol_version(p)) < 0) {
+ error = errno;
+ goto cleanup;
+ }
+
+ if (rt > latest_version || rt == expected_version) {
+ free(*path);
+ if ((*path = strdup(p)) == NULL) {
+ error = errno;
+ goto cleanup;
+ }
+ if (rt == expected_version) {
+ break;
+ }
+ latest_version = rt;
+ }
+ }
+
+ if (*path == NULL) {
+ retval = 1;
+ } else {
+ retval = 0;
+ }
+ cleanup:
+ free(pattern);
+ globfree(&glob_buf);
+ if (retval == -1) {
+ errno = error;
+ }
+ return retval;
+}
+
+int qpol_default_policy_find(char **path)
+{
+ int rt;
+ if (path == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ *path = NULL;
+ /* Try default source policy first as a source policy contains
+ * more useful information. */
+ if ((rt = search_policy_source_file(path)) <= 0) {
+ return rt;
+ }
+ /* Try a binary policy */
+ return search_policy_binary_file(path);
+}
+
+#include <stdlib.h>
+#include <bzlib.h>
+#include <string.h>
+#include <sys/sendfile.h>
+
+#define BZ2_MAGICSTR "BZh"
+#define BZ2_MAGICLEN (sizeof(BZ2_MAGICSTR)-1)
+
+/* qpol_bunzip() uncompresses a file to '*data', returning the total number of
+ * uncompressed bytes in the file.
+ * Returns -1 if file could not be decompressed.
+ * Originally from libsemanage/src/direct_api.c, with slight mods */
+ssize_t qpol_bunzip(FILE *f, char **data)
+{
+ BZFILE* b;
+ size_t nBuf;
+ char buf[1<<18];
+ size_t size = sizeof(buf);
+ int bzerror;
+ size_t total=0;
+ int small=0; // Set to 1 to use less memory decompressing (about 2x slower)
+
+ bzerror = fread(buf, 1, BZ2_MAGICLEN, f);
+ rewind(f);
+ if ((bzerror != BZ2_MAGICLEN) || memcmp(buf, BZ2_MAGICSTR, BZ2_MAGICLEN))
+ return -1;
+
+ b = BZ2_bzReadOpen ( &bzerror, f, 0, small, NULL, 0 );
+ if ( bzerror != BZ_OK ) {
+ BZ2_bzReadClose ( &bzerror, b );
+ return -1;
+ }
+
+ char *uncompress = realloc(NULL, size);
+
+ while ( bzerror == BZ_OK) {
+ nBuf = BZ2_bzRead ( &bzerror, b, buf, sizeof(buf));
+ if (( bzerror == BZ_OK ) || ( bzerror == BZ_STREAM_END )) {
+ if (total + nBuf > size) {
+ size *= 2;
+ uncompress = realloc(uncompress, size);
+ }
+ memcpy(&uncompress[total], buf, nBuf);
+ total += nBuf;
+ }
+ }
+ if ( bzerror != BZ_STREAM_END ) {
+ BZ2_bzReadClose ( &bzerror, b );
+ free(uncompress);
+ return -1;
+ }
+ BZ2_bzReadClose ( &bzerror, b );
+
+ *data = uncompress;
+ return total;
+}
+
diff --git a/libqpol/swig/Makefile.am b/libqpol/swig/Makefile.am
new file mode 100644
index 0000000..b1e2d4e
--- /dev/null
+++ b/libqpol/swig/Makefile.am
@@ -0,0 +1,15 @@
+if DO_SWIGIFY_PYTHON
+ MAYBE_PYSWIG = python
+endif
+
+if DO_SWIGIFY_JAVA
+ MAYBE_JSWIG = java
+endif
+
+if DO_SWIGIFY_TCL
+ MAYBE_TCLSWIG = tcl
+endif
+
+SUBDIRS = $(MAYBE_PYSWIG) $(MAYBE_JSWIG) $(MAYBE_TCLSWIG)
+
+dist_noinst_DATA = qpol.i
diff --git a/libqpol/swig/java/MANIFEST.MF.in b/libqpol/swig/java/MANIFEST.MF.in
new file mode 100644
index 0000000..0cd71bf
--- /dev/null
+++ b/libqpol/swig/java/MANIFEST.MF.in
@@ -0,0 +1,9 @@
+Manifest-Version: 1.0
+
+Name: com/tresys/setools/
+Specification-Title: "SETools Java Libraries"
+Specification-Version: "@VERSION@"
+Specification-Vendor: "Tresys Technology"
+Implementation-Title: "com.tresys.setools.qpol"
+Implementation-Version: "@libqpol_version@"
+Implementation-Vendor: "Tresys Technology"
diff --git a/libqpol/swig/java/Makefile.am b/libqpol/swig/java/Makefile.am
new file mode 100644
index 0000000..a25eacb
--- /dev/null
+++ b/libqpol/swig/java/Makefile.am
@@ -0,0 +1,97 @@
+wrappedso_DATA = libjqpol.so.@libqpol_version@
+wrappedso_SONAME = @libqpol_jswig_soname@
+short_name = libjqpol.so
+wrappedsodir = $(libdir)
+
+package_name = com.tresys.setools.qpol
+package_dir = $(dir $(subst .,/,$(package_name)))qpol
+
+wrappedjar_DATA = qpol.jar
+wrappedjardir = $(setoolsdir)
+
+dist_noinst_DATA = $(srcdir)/../qpol.i
+BUILT_SOURCES = qpol_wrap.c \
+ qpol_avrule_t.java \
+ qpol_bool_t.java \
+ qpol_capability_e.java \
+ qpol_cat_t.java \
+ qpol_class_t.java \
+ qpol_common_t.java \
+ qpol_cond_expr_node_t.java \
+ qpol_cond_t.java \
+ qpolConstants.java \
+ qpol_constraint_expr_node_t.java \
+ qpol_constraint_t.java \
+ qpol_context_t.java \
+ qpol_fs_use_t.java \
+ qpol_genfscon_t.java \
+ qpol_isid_t.java \
+ qpol_iterator_t.java \
+ qpol.java \
+ qpolJNI.java \
+ qpol_level_t.java \
+ qpol_mls_level_t.java \
+ qpol_mls_range_t.java \
+ qpol_module_t.java \
+ qpol_netifcon_t.java \
+ qpol_nodecon_t.java \
+ qpol_policy_t.java \
+ qpol_portcon_t.java \
+ qpol_range_trans_t.java \
+ qpol_role_allow_t.java \
+ qpol_role_t.java \
+ qpol_role_trans_t.java \
+ qpol_syn_avrule_t.java \
+ qpol_syn_terule_t.java \
+ qpol_terule_t.java \
+ qpol_type_set_t.java \
+ qpol_type_t.java \
+ qpol_user_t.java \
+ qpol_validatetrans_t.java \
+ SWIGTYPE_p_int.java \
+ SWIGTYPE_p_unsigned_int.java \
+ SWIGTYPE_p_void.java
+
+AM_CFLAGS = @DEBUGCFLAGS@ @WARNCFLAGS@ @PROFILECFLAGS@ @SELINUX_CFLAGS@ \
+ -I$(top_builddir) -fpic \
+ -I$(top_srcdir)/libqpol/include
+AM_JFLAGS = @DEBUGJFLAGS@ @WARNJFLAGS@
+AM_LDFLAGS = @DEBUGLDFLAGS@ @WARNLDFLAGS@ @PROFILELDFLAGS@ @QPOL_LIB_FLAG@
+
+$(firstword $(BUILT_SOURCES)): $(dist_noinst_DATA) $(DEPENDENCIES)
+ $(SWIG) $(SWIG_JAVA_OPT) -package $(package_name) -o $@ -I$(top_srcdir)/libqpol/include $<
+
+$(wordlist 2,$(words $(BUILT_SOURCES)), $(BUILT_SOURCES)): $(firstword $(BUILT_SOURCES))
+
+$(wrappedso_DATA): $(filter %.c, $(BUILT_SOURCES))
+ $(CC) -shared -o $@ $^ $(AM_CFLAGS) $(CFLAGS) $(SWIG_JAVA_CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -Wl,-soname,$(wrappedso_SONAME)
+ $(LN_S) -f $@ $(wrappedso_SONAME)
+ $(LN_S) -f $@ $(short_name)
+
+classes = $(patsubst %.java,$(package_dir)/%.class,$(filter %.java, $(BUILT_SOURCES)))
+
+# Because the Java compiler can generate multiple class files from the
+# same source .java file, putting all of the classes below will result
+# in repeated invocations of javac. Therefore, an alternative is to
+# just depend upon the first class file, and let the Java compiler
+# create the rest of them.
+$(firstword $(classes)): $(filter %.java, $(BUILT_SOURCES))
+ $(JAVAC) $(AM_JFLAGS) $(JAVAFLAGS) -d . $^
+
+$(wordlist 2,$(words $(classes)),$(classes)): $(firstword $(classes))
+
+$(wrappedjar_DATA): MANIFEST.MF
+
+$(wrappedjar_DATA): $(classes)
+ $(JAR) cfm $@ MANIFEST.MF $^
+
+install-data-hook:
+ cd $(DESTDIR)$(wrappedsodir) && $(LN_S) -f $(wrappedso_DATA) $(wrappedso_SONAME)
+ cd $(DESTDIR)$(wrappedsodir) && $(LN_S) -f $(wrappedso_DATA) $(short_name)
+ $(mkdir_p) $(DESTDIR)$(javadir) && cd $(DESTDIR)$(javadir) && $(LN_S) -f $(wrappedjardir)/$(wrappedjar_DATA)
+
+uninstall-local:
+ -rm -rf $(DESTDIR)$(wrappedsodir)/$(wrappedso_SONAME) $(DESTDIR)$(wrappedsodir)/$(short_name)
+ -rm -f $(DESTDIR)$(javadir)/$(wrappedjar_DATA)
+
+MOSTLYCLEANFILES = $(BUILT_SOURCES) $(classes) $(wrappedso_DATA) $(wrappedjar_DATA) $(wrappedso_SONAME) $(short_name)
diff --git a/libqpol/swig/python/Makefile.am b/libqpol/swig/python/Makefile.am
new file mode 100644
index 0000000..cc6d681
--- /dev/null
+++ b/libqpol/swig/python/Makefile.am
@@ -0,0 +1,34 @@
+wrappedso_DATA = _qpol.so.@libqpol_version@
+wrappedso_SONAME = @libqpol_pyswig_soname@
+wrappedsodir = $(pkgpyexecdir)
+
+pkgpython_PYTHON = __init__.py
+wrappedpy_DATA = qpol.py $(pkgpython_PYTHON)
+wrappedpydir = $(pkgpyexecdir)
+
+dist_noinst_DATA = $(srcdir)/../qpol.i
+BUILT_SOURCES = qpol_wrap.c
+
+AM_CFLAGS = @DEBUGCFLAGS@ @WARNCFLAGS@ @PROFILECFLAGS@ @SELINUX_CFLAGS@ \
+ -I$(top_builddir) -fpic \
+ -I$(top_srcdir)/libqpol/include
+AM_LDFLAGS = @DEBUGLDFLAGS@ @WARNLDFLAGS@ @PROFILELDFLAGS@ @QPOL_LIB_FLAG@ @PYTHON_LDFLAGS@
+
+$(BUILT_SOURCES): $(dist_noinst_DATA) $(DEPENDENCIES)
+ $(SWIG) $(SWIG_PYTHON_OPT) -o $@ $<
+
+$(wrappedso_DATA): $(BUILT_SOURCES)
+ $(CC) -shared -o $@ $^ $(AM_CFLAGS) $(CFLAGS) $(SWIG_PYTHON_CPPFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -Wl,-soname,$(wrappedso_SONAME)
+ $(LN_S) -f $@ $(wrappedso_SONAME)
+ $(LN_S) -f $@ _qpol.so
+
+$(wrappedpy_DATA): $(BUILT_SOURCES)
+
+install-data-hook:
+ cd $(DESTDIR)$(wrappedsodir) && $(LN_S) -f $(wrappedso_DATA) $(wrappedso_SONAME)
+ cd $(DESTDIR)$(wrappedsodir) && $(LN_S) -f $(wrappedso_DATA) _qpol.so
+
+uninstall-local:
+ -rm -rf $(DESTDIR)$(wrappedsodir)/$(wrappedso_SONAME) $(DESTDIR)$(wrappedsodir)/_qpol.so
+
+MOSTLYCLEANFILES = $(BUILT_SOURCES) $(wrappedso_DATA) qpol.py $(wrappedso_SONAME) _qpol.so qpol.pyc
diff --git a/libqpol/swig/python/__init__.py b/libqpol/swig/python/__init__.py
new file mode 100644
index 0000000..218d892
--- /dev/null
+++ b/libqpol/swig/python/__init__.py
@@ -0,0 +1 @@
+# This file intentionally left blank.
diff --git a/libqpol/swig/qpol.i b/libqpol/swig/qpol.i
new file mode 100644
index 0000000..45a2403
--- /dev/null
+++ b/libqpol/swig/qpol.i
@@ -0,0 +1,2879 @@
+/**
+ * SWIG declarations for libqpol.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2006-2008 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 qpol
+
+%{
+#include "../include/qpol/avrule_query.h"
+#include "../include/qpol/bool_query.h"
+#include "../include/qpol/class_perm_query.h"
+#include "../include/qpol/cond_query.h"
+#include "../include/qpol/constraint_query.h"
+#include "../include/qpol/context_query.h"
+#include "../include/qpol/fs_use_query.h"
+#include "../include/qpol/genfscon_query.h"
+#include "../include/qpol/isid_query.h"
+#include "../include/qpol/iterator.h"
+#include "../include/qpol/mls_query.h"
+#include "../include/qpol/mlsrule_query.h"
+#include "../include/qpol/module.h"
+#include "../include/qpol/netifcon_query.h"
+#include "../include/qpol/nodecon_query.h"
+#include "../include/qpol/policy.h"
+#include "../include/qpol/policy_extend.h"
+#include "../include/qpol/portcon_query.h"
+#include "../include/qpol/rbacrule_query.h"
+#include "../include/qpol/role_query.h"
+#include "../include/qpol/syn_rule_query.h"
+#include "../include/qpol/terule_query.h"
+#include "../include/qpol/type_query.h"
+#include "../include/qpol/user_query.h"
+#include "../include/qpol/util.h"
+
+/* Provide hooks so that language-specific modules can define the
+ * callback function, used by the handler in
+ * qpol_policy_open_from_file().
+ */
+SWIGEXPORT qpol_callback_fn_t qpol_swig_message_callback = NULL;
+SWIGEXPORT void * qpol_swig_message_callback_arg = NULL;
+
+%}
+
+#ifdef SWIGJAVA
+%javaconst(1);
+/* get the java environment so we can throw exceptions */
+%{
+ static JNIEnv *qpol_global_jenv;
+ jint JNI_OnLoad(JavaVM *vm, void *reserved) {
+ (*vm)->AttachCurrentThread(vm, (void **)&qpol_global_jenv, NULL);
+ return JNI_VERSION_1_2;
+ }
+%}
+#endif
+
+%include exception.i
+%include stdint.i
+
+%{
+#undef BEGIN_EXCEPTION
+#undef END_EXCEPTION
+%}
+
+#ifdef SWIGJAVA
+
+%exception {
+ qpol_global_jenv = jenv;
+ $action
+}
+
+%{
+#define BEGIN_EXCEPTION JNIEnv *local_jenv = qpol_global_jenv; {
+#define END_EXCEPTION }
+%}
+
+/* handle size_t correctly in java as architecture independent */
+%typemap(jni) size_t "jlong"
+%typemap(jtype) size_t "long"
+%typemap(jstype) size_t "long"
+%typemap(javabody) SWIGTYPE, void* %{
+ private long swigCPtr;
+ protected boolean swigCMemOwn;
+
+ public $javaclassname(long cPtr, boolean cMemoryOwn) {
+ swigCMemOwn = cMemoryOwn;
+ swigCPtr = cPtr;
+ }
+
+ public static long getCPtr($javaclassname obj) {
+ return (obj == null) ? 0 : obj.swigCPtr;
+ }
+%}
+%pragma(java) jniclasscode=%{
+ static {
+ try
+ {
+ libqpol_get_version();
+ }
+ catch (UnsatisfiedLinkError ule)
+ {
+ System.loadLibrary("jqpol");
+ }
+ }
+%}
+
+#else
+/* not in java so handle size_t as architecture dependent */
+#ifdef SWIGWORDSIZE64
+typedef uint64_t size_t;
+#else
+typedef uint32_t size_t;
+#endif
+%{
+#define BEGIN_EXCEPTION
+#define END_EXCEPTION
+%}
+#endif
+
+/* utility functions */
+const char *libqpol_get_version(void);
+
+%rename(qpol_default_policy_find) wrap_qpol_default_policy_find;
+%newobject wrap_qpol_default_policy_find();
+
+/* if java, pass the new exception macro to C not just SWIG */
+#ifdef SWIGJAVA
+#undef SWIG_exception
+#define SWIG_exception(code, msg) {SWIG_JavaException(local_jenv, code, msg); goto fail;}
+%inline %{
+#undef SWIG_exception
+#define SWIG_exception(code, msg) {SWIG_JavaException(local_jenv, code, msg); goto fail;}
+%}
+#endif
+
+#ifdef SWIGTCL
+/* implement a custom non thread-safe error handler */
+%{
+static char *message = NULL;
+static void tcl_clear_error(void)
+{
+ free(message);
+ message = NULL;
+}
+static void tcl_throw_error(const char *s)
+{
+ free(message);
+ message = strdup(s);
+}
+static char *tcl_get_error(void)
+{
+ return message;
+}
+#undef SWIG_exception
+#define SWIG_exception(code, msg) {tcl_throw_error(msg); goto fail;}
+%}
+
+%wrapper %{
+/* Tcl module's initialization routine is expected to be named
+ * Qpol_Init(), but the output file will be called libtqpol.so instead
+ * of libqpol.so. Therefore add an alias from Tqpol_Init() to the
+ * real Qpol_Init().
+ */
+SWIGEXPORT int Tqpol_Init(Tcl_Interp *interp) {
+ return SWIG_init(interp);
+}
+%}
+
+%exception {
+ char *err;
+ tcl_clear_error();
+ $action
+ if ((err = tcl_get_error()) != NULL) {
+ Tcl_Obj *obj = Tcl_NewStringObj(message, -1);
+ Tcl_ResetResult(interp);
+ Tcl_SetObjResult(interp, obj);
+ goto fail;
+ }
+}
+#undef SWIG_exception
+#define SWIG_exception(code, msg) {tcl_throw_error(msg); goto fail;}
+#endif
+
+%inline %{
+ /* cast void * to char * as it can't have a constructor */
+ const char * to_str(void *x) {
+ return (const char *)x;
+ }
+
+ char * wrap_qpol_default_policy_find() {
+ char *path;
+ int retv;
+ BEGIN_EXCEPTION
+ retv = qpol_default_policy_find(&path);
+ if (retv < 0) {
+ SWIG_exception(SWIG_IOError, "Error searching for default policy");
+ } else if (retv > 0) {
+ SWIG_exception(SWIG_RuntimeError, "Could not find default policy");
+ } else {
+ return path;
+ }
+ END_EXCEPTION
+ fail: /* SWIG_exception calls goto fail */
+ return NULL;
+ }
+%}
+
+/* qpol_module */
+#define QPOL_MODULE_UNKNOWN 0
+#define QPOL_MODULE_BASE 1
+#define QPOL_MODULE_OTHER 2
+typedef struct qpol_module {} qpol_module_t;
+%extend qpol_module_t {
+ qpol_module_t(const char *path) {
+ qpol_module_t *m;
+ BEGIN_EXCEPTION
+ if (qpol_module_create_from_file(path, &m)) {
+ SWIG_exception(SWIG_IOError, "Error opening module");
+ }
+ return m;
+ END_EXCEPTION
+ fail:
+ return NULL;
+ };
+ ~qpol_module_t() {
+ qpol_module_destroy(&self);
+ };
+ const char *get_path() {
+ const char *p;
+ BEGIN_EXCEPTION
+ if (qpol_module_get_path(self, &p)) {
+ SWIG_exception(SWIG_ValueError,"Could not get module path");
+ }
+ return p;
+ END_EXCEPTION
+ fail:
+ return NULL;
+ };
+ const char *get_name() {
+ const char *n;
+ BEGIN_EXCEPTION
+ if (qpol_module_get_name(self, &n)) {
+ SWIG_exception(SWIG_ValueError,"Could not get module name");
+ }
+ return n;
+ END_EXCEPTION
+ fail:
+ return NULL;
+ };
+ const char *get_version() {
+ const char *v;
+ BEGIN_EXCEPTION
+ if (qpol_module_get_version(self, &v)) {
+ SWIG_exception(SWIG_ValueError,"Could not get module version");
+ }
+ return v;
+ END_EXCEPTION
+ fail:
+ return NULL;
+ };
+ int get_type() {
+ int t;
+ BEGIN_EXCEPTION
+ if (qpol_module_get_type(self, &t)) {
+ SWIG_exception(SWIG_ValueError,"Could not get module type");
+ }
+ END_EXCEPTION
+ fail:
+ return t;
+ };
+ int get_enabled() {
+ int e;
+ BEGIN_EXCEPTION
+ if (qpol_module_get_enabled(self, &e)) {
+ SWIG_exception(SWIG_ValueError,"Could not get module state");
+ }
+ END_EXCEPTION
+ fail:
+ return e;
+ };
+ void set_enabled(int state) {
+ BEGIN_EXCEPTION
+ if (qpol_module_set_enabled(self, state)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not set module state");
+ }
+ END_EXCEPTION
+ fail:
+ return;
+ };
+};
+
+/* qpol_policy */
+#define QPOL_POLICY_OPTION_NO_NEVERALLOWS 0x00000001
+#define QPOL_POLICY_OPTION_NO_RULES 0x00000002
+#define QPOL_POLICY_OPTION_MATCH_SYSTEM 0x00000004
+typedef struct qpol_policy {} qpol_policy_t;
+typedef void (*qpol_callback_fn_t) (void *varg, struct qpol_policy * policy, int level, const char *fmt, va_list va_args);
+#define QPOL_POLICY_UNKNOWN -1
+#define QPOL_POLICY_KERNEL_SOURCE 0
+#define QPOL_POLICY_KERNEL_BINARY 1
+#define QPOL_POLICY_MODULE_BINARY 2
+typedef enum qpol_capability
+{
+ QPOL_CAP_ATTRIB_NAMES,
+ QPOL_CAP_SYN_RULES,
+ QPOL_CAP_LINE_NUMBERS,
+ QPOL_CAP_CONDITIONALS,
+ QPOL_CAP_MLS,
+ QPOL_CAP_MODULES,
+ QPOL_CAP_RULES_LOADED,
+ QPOL_CAP_SOURCE,
+ QPOL_CAP_NEVERALLOW
+} qpol_capability_e;
+
+%extend qpol_policy_t {
+ qpol_policy_t(const char *path, const int options) {
+ qpol_policy_t *p;
+ BEGIN_EXCEPTION
+ if (qpol_policy_open_from_file(path, &p, qpol_swig_message_callback, qpol_swig_message_callback_arg, options) < 0) {
+ SWIG_exception(SWIG_IOError, "Error opening policy");
+ }
+ END_EXCEPTION
+ return p;
+ fail:
+ return NULL;
+ }
+ ~qpol_policy_t() {
+ qpol_policy_destroy(&self);
+ };
+ void reevaluate_conds() {
+ BEGIN_EXCEPTION
+ if (qpol_policy_reevaluate_conds(self)) {
+ SWIG_exception(SWIG_ValueError, "Error evaluating conditional expressions");
+ }
+ END_EXCEPTION
+ fail:
+ return;
+ };
+ void append_module(qpol_module_t *mod) {
+ BEGIN_EXCEPTION
+ if (qpol_policy_append_module(self, mod)) {
+ SWIG_exception(SWIG_MemoryError, "Out of Memory");
+ }
+ END_EXCEPTION
+ fail:
+ return;
+ };
+ void rebuild (const int options) {
+ BEGIN_EXCEPTION
+ if (qpol_policy_rebuild(self, options)) {
+ SWIG_exception(SWIG_RuntimeError, "Failed rebuilding policy");
+ }
+ END_EXCEPTION
+ fail:
+ return;
+ };
+ int get_version () {
+ unsigned int v;
+ (void)qpol_policy_get_policy_version(self, &v); /* only error is on null parameters neither can be here */
+ return (int) v;
+ };
+ int get_type () {
+ int t;
+ (void)qpol_policy_get_type(self, &t); /* only error is on null parameters neither can be here */
+ return t;
+ };
+ int has_capability (qpol_capability_e cap) {
+ return qpol_policy_has_capability(self, cap);
+ };
+ void build_syn_rule_table() {
+ BEGIN_EXCEPTION
+ if (qpol_policy_build_syn_rule_table(self)) {
+ SWIG_exception(SWIG_MemoryError, "Out of Memory");
+ }
+ END_EXCEPTION
+ fail:
+ return;
+ };
+ %newobject get_module_iter();
+ qpol_iterator_t *get_module_iter() {
+ BEGIN_EXCEPTION
+ qpol_iterator_t *iter;
+ if (qpol_policy_get_module_iter(self, &iter)) {
+ SWIG_exception(SWIG_MemoryError, "Out of Memory");
+ }
+ return iter;
+ END_EXCEPTION
+ fail:
+ return NULL;
+ };
+ %newobject get_type_iter();
+ qpol_iterator_t *get_type_iter() {
+ BEGIN_EXCEPTION
+ qpol_iterator_t *iter;
+ if (qpol_policy_get_type_iter(self, &iter)) {
+ SWIG_exception(SWIG_MemoryError, "Out of Memory");
+ }
+ return iter;
+ END_EXCEPTION
+ fail:
+ return NULL;
+ };
+ %newobject get_role_iter();
+ qpol_iterator_t *get_role_iter() {
+ BEGIN_EXCEPTION
+ qpol_iterator_t *iter;
+ if (qpol_policy_get_role_iter(self, &iter)) {
+ SWIG_exception(SWIG_MemoryError, "Out of Memory");
+ }
+ return iter;
+ END_EXCEPTION
+ fail:
+ return NULL;
+ };
+ %newobject get_level_iter();
+ qpol_iterator_t *get_level_iter() {
+ BEGIN_EXCEPTION
+ qpol_iterator_t *iter;
+ if (qpol_policy_get_level_iter(self, &iter)) {
+ SWIG_exception(SWIG_MemoryError, "Out of Memory");
+ }
+ return iter;
+ END_EXCEPTION
+ fail:
+ return NULL;
+ };
+ %newobject get_cat_iter();
+ qpol_iterator_t *get_cat_iter() {
+ BEGIN_EXCEPTION
+ qpol_iterator_t *iter;
+ if (qpol_policy_get_cat_iter(self, &iter)) {
+ SWIG_exception(SWIG_MemoryError, "Out of Memory");
+ }
+ return iter;
+ END_EXCEPTION
+ fail:
+ return NULL;
+ };
+ %newobject get_user_iter();
+ qpol_iterator_t *get_user_iter() {
+ BEGIN_EXCEPTION
+ qpol_iterator_t *iter;
+ if (qpol_policy_get_user_iter(self, &iter)) {
+ SWIG_exception(SWIG_MemoryError, "Out of Memory");
+ }
+ return iter;
+ END_EXCEPTION
+ fail:
+ return NULL;
+ };
+ %newobject get_bool_iter();
+ qpol_iterator_t *get_bool_iter() {
+ BEGIN_EXCEPTION
+ qpol_iterator_t *iter;
+ if (qpol_policy_get_bool_iter(self, &iter)) {
+ SWIG_exception(SWIG_MemoryError, "Out of Memory");
+ }
+ return iter;
+ END_EXCEPTION
+ fail:
+ return NULL;
+ };
+ %newobject get_class_iter(char*);
+ qpol_iterator_t *get_class_iter(char *perm=NULL) {
+ BEGIN_EXCEPTION
+ qpol_iterator_t *iter;
+ if (perm) {
+ if (qpol_perm_get_class_iter(self, perm, &iter)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not get class iterator");
+ }
+ } else {
+ if (qpol_policy_get_class_iter(self, &iter)) {
+ SWIG_exception(SWIG_MemoryError, "Out of Memory");
+ }
+ }
+ return iter;
+ END_EXCEPTION
+ fail:
+ return NULL;
+ };
+ %newobject get_common_iter(char*);
+ qpol_iterator_t *get_common_iter(char *perm=NULL) {
+ BEGIN_EXCEPTION
+ qpol_iterator_t *iter;
+ if (perm) {
+ if (qpol_perm_get_common_iter(self, perm, &iter)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not get common iterator");
+ }
+ } else {
+ if (qpol_policy_get_common_iter(self, &iter)) {
+ SWIG_exception(SWIG_MemoryError, "Out of Memory");
+ }
+ }
+ return iter;
+ END_EXCEPTION
+ fail:
+ return NULL;
+ };
+ %newobject get_fs_use_iter();
+ qpol_iterator_t *get_fs_use_iter() {
+ BEGIN_EXCEPTION
+ qpol_iterator_t *iter;
+ if (qpol_policy_get_fs_use_iter(self, &iter)) {
+ SWIG_exception(SWIG_MemoryError, "Out of Memory");
+ }
+ return iter;
+ END_EXCEPTION
+ fail:
+ return NULL;
+ };
+ %newobject get_genfscon_iter();
+ qpol_iterator_t *get_genfscon_iter() {
+ BEGIN_EXCEPTION
+ qpol_iterator_t *iter;
+ if (qpol_policy_get_genfscon_iter(self, &iter)) {
+ SWIG_exception(SWIG_MemoryError, "Out of Memory");
+ }
+ return iter;
+ END_EXCEPTION
+ fail:
+ return NULL;
+ };
+ %newobject get_isid_iter();
+ qpol_iterator_t *get_isid_iter() {
+ BEGIN_EXCEPTION
+ qpol_iterator_t *iter;
+ if (qpol_policy_get_isid_iter(self, &iter)) {
+ SWIG_exception(SWIG_MemoryError, "Out of Memory");
+ }
+ return iter;
+ END_EXCEPTION
+ fail:
+ return NULL;
+ };
+ %newobject get_netifcon_iter();
+ qpol_iterator_t *get_netifcon_iter() {
+ BEGIN_EXCEPTION
+ qpol_iterator_t *iter;
+ if (qpol_policy_get_netifcon_iter(self, &iter)) {
+ SWIG_exception(SWIG_MemoryError, "Out of Memory");
+ }
+ return iter;
+ END_EXCEPTION
+ fail:
+ return NULL;
+ };
+ %newobject get_nodecon_iter();
+ qpol_iterator_t *get_nodecon_iter() {
+ BEGIN_EXCEPTION
+ qpol_iterator_t *iter;
+ if (qpol_policy_get_nodecon_iter(self, &iter)) {
+ SWIG_exception(SWIG_MemoryError, "Out of Memory");
+ }
+ return iter;
+ END_EXCEPTION
+ fail:
+ return NULL;
+ };
+ %newobject get_portcon_iter();
+ qpol_iterator_t *get_portcon_iter() {
+ BEGIN_EXCEPTION
+ qpol_iterator_t *iter;
+ if (qpol_policy_get_portcon_iter(self, &iter)) {
+ SWIG_exception(SWIG_MemoryError, "Out of Memory");
+ }
+ return iter;
+ END_EXCEPTION
+ fail:
+ return NULL;
+ };
+ %newobject get_constraint_iter();
+ qpol_iterator_t *get_constraint_iter() {
+ BEGIN_EXCEPTION
+ qpol_iterator_t *iter;
+ if (qpol_policy_get_constraint_iter(self, &iter)) {
+ SWIG_exception(SWIG_MemoryError, "Out of Memory");
+ }
+ return iter;
+ END_EXCEPTION
+ fail:
+ return NULL;
+ };
+ %newobject get_validatetrans_iter();
+ qpol_iterator_t *get_validatetrans_iter() {
+ BEGIN_EXCEPTION
+ qpol_iterator_t *iter;
+ if (qpol_policy_get_validatetrans_iter(self, &iter)) {
+ SWIG_exception(SWIG_MemoryError, "Out of Memory");
+ }
+ return iter;
+ END_EXCEPTION
+ fail:
+ return NULL;
+ };
+ %newobject get_role_allow_iter();
+ qpol_iterator_t *get_role_allow_iter() {
+ BEGIN_EXCEPTION
+ qpol_iterator_t *iter;
+ if (qpol_policy_get_role_allow_iter(self, &iter)) {
+ SWIG_exception(SWIG_MemoryError, "Out of Memory");
+ }
+ return iter;
+ END_EXCEPTION
+ fail:
+ return NULL;
+ };
+ %newobject get_role_trans_iter();
+ qpol_iterator_t *get_role_trans_iter() {
+ BEGIN_EXCEPTION
+ qpol_iterator_t *iter;
+ if (qpol_policy_get_role_trans_iter(self, &iter)) {
+ SWIG_exception(SWIG_MemoryError, "Out of Memory");
+ }
+ return iter;
+ END_EXCEPTION
+ fail:
+ return NULL;
+ };
+ %newobject get_range_trans_iter();
+ qpol_iterator_t *get_range_trans_iter() {
+ BEGIN_EXCEPTION
+ qpol_iterator_t *iter;
+ if (qpol_policy_get_range_trans_iter(self, &iter)) {
+ SWIG_exception(SWIG_MemoryError, "Out of Memory");
+ }
+ return iter;
+ END_EXCEPTION
+ fail:
+ return NULL;
+ };
+ %newobject get_avrule_iter(int);
+ qpol_iterator_t *get_avrule_iter(int rule_types) {
+ BEGIN_EXCEPTION
+ qpol_iterator_t *iter;
+ if (qpol_policy_get_avrule_iter(self, rule_types, &iter)) {
+ SWIG_exception(SWIG_MemoryError, "Out of Memory");
+ }
+ return iter;
+ END_EXCEPTION
+ fail:
+ return NULL;
+ };
+ %newobject get_terule_iter(int);
+ qpol_iterator_t *get_terule_iter(int rule_types) {
+ BEGIN_EXCEPTION
+ qpol_iterator_t *iter;
+ if (qpol_policy_get_terule_iter(self, rule_types, &iter)) {
+ SWIG_exception(SWIG_MemoryError, "Out of Memory");
+ }
+ return iter;
+ END_EXCEPTION
+ fail:
+ return NULL;
+ };
+ %newobject get_cond_iter();
+ qpol_iterator_t *get_cond_iter() {
+ BEGIN_EXCEPTION
+ qpol_iterator_t *iter;
+ if (qpol_policy_get_cond_iter(self, &iter)) {
+ SWIG_exception(SWIG_MemoryError, "Out of Memory");
+ }
+ return iter;
+ END_EXCEPTION
+ fail:
+ return NULL;
+ };
+};
+
+/* qpol iterator */
+typedef struct qpol_iterator {} qpol_iterator_t;
+%extend qpol_iterator_t {
+ /* user never directly creates, but SWIG expects a constructor */
+ qpol_iterator_t() {
+ BEGIN_EXCEPTION
+ SWIG_exception(SWIG_TypeError, "User may not create iterators difectly");
+ END_EXCEPTION
+ fail:
+ return NULL;
+ };
+ ~qpol_iterator_t() {
+ qpol_iterator_destroy(&self);
+ };
+ void *get_item() {
+ BEGIN_EXCEPTION
+ void *i;
+ if (qpol_iterator_get_item(self, &i)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not get item");
+ }
+ return i;
+ END_EXCEPTION
+ fail:
+ return NULL;
+ };
+ void next() {
+ BEGIN_EXCEPTION
+ if (qpol_iterator_next(self)) {
+ SWIG_exception(SWIG_RuntimeError, "Error advancing iterator");
+ }
+ END_EXCEPTION
+ fail:
+ return;
+ };
+ int end() {
+ return qpol_iterator_end(self);
+ };
+ size_t get_size() {
+ BEGIN_EXCEPTION
+ size_t s;
+ if (qpol_iterator_get_size(self, &s)) {
+ SWIG_exception(SWIG_ValueError, "Could not get iterator size");
+ }
+ return s;
+ END_EXCEPTION
+ fail:
+ return 0;
+ };
+};
+
+/* qpol type */
+typedef struct qpol_type {} qpol_type_t;
+%extend qpol_type_t {
+ qpol_type_t(qpol_policy_t *p, const char *name) {
+ BEGIN_EXCEPTION
+ const qpol_type_t *t;
+ if (qpol_policy_get_type_by_name(p, name, &t)) {
+ SWIG_exception(SWIG_RuntimeError, "Type does not exist");
+ }
+ return (qpol_type_t*)t;
+ END_EXCEPTION
+ fail:
+ return NULL;
+ };
+ ~qpol_type_t() {
+ /* no op */
+ return;
+ };
+ const char *get_name(qpol_policy_t *p) {
+ BEGIN_EXCEPTION
+ const char *name;
+ if (qpol_type_get_name(p, self, &name)) {
+ SWIG_exception(SWIG_ValueError, "Could not get type name");
+ }
+ return name;
+ END_EXCEPTION
+ fail:
+ return NULL;
+ };
+ int get_value(qpol_policy_t *p) {
+ uint32_t v;
+ BEGIN_EXCEPTION
+ if (qpol_type_get_value(p, self, &v)) {
+ SWIG_exception(SWIG_ValueError, "Could not get type value");
+ }
+ END_EXCEPTION
+ fail:
+ return (int) v;
+ };
+ int get_isalias(qpol_policy_t *p) {
+ unsigned char i;
+ BEGIN_EXCEPTION
+ if (qpol_type_get_isalias(p, self, &i)) {
+ SWIG_exception(SWIG_ValueError, "Could not determine whether type is an alias");
+ }
+ END_EXCEPTION
+ fail:
+ return (int)i;
+ };
+ int get_isattr(qpol_policy_t *p) {
+ unsigned char i;
+ BEGIN_EXCEPTION
+ if (qpol_type_get_isattr(p, self, &i)) {
+ SWIG_exception(SWIG_ValueError, "Could not determine whether type is an attribute");
+ }
+ END_EXCEPTION
+ fail:
+ return (int)i;
+ };
+ int get_ispermissive(qpol_policy_t *p) {
+ unsigned char i;
+ BEGIN_EXCEPTION
+ if (qpol_type_get_ispermissive(p, self, &i)) {
+ SWIG_exception(SWIG_ValueError, "Could not determine whether type is permissive");
+ }
+ END_EXCEPTION
+ fail:
+ return (int)i;
+ };
+ %newobject get_type_iter(qpol_policy_t*);
+ qpol_iterator_t *get_type_iter(qpol_policy_t *p) {
+ qpol_iterator_t *iter;
+ BEGIN_EXCEPTION
+ int retv = qpol_type_get_type_iter(p, self, &iter);
+ if (retv < 0) {
+ SWIG_exception(SWIG_RuntimeError, "Could not get attribute types");
+ } else if (retv > 0) {
+ SWIG_exception(SWIG_TypeError, "Type is not an attribute");
+ }
+ END_EXCEPTION
+ fail:
+ return iter;
+ };
+ %newobject get_attr_iter(qpol_policy_t*);
+ qpol_iterator_t *get_attr_iter(qpol_policy_t *p) {
+ qpol_iterator_t *iter;
+ BEGIN_EXCEPTION
+ int retv = qpol_type_get_attr_iter(p, self, &iter);
+ if (retv < 0) {
+ SWIG_exception(SWIG_RuntimeError, "Could not get type attributes");
+ } else if (retv > 0) {
+ SWIG_exception(SWIG_TypeError, "Type is an attribute");
+ }
+ END_EXCEPTION
+ fail:
+ return iter;
+ };
+ %newobject get_alias_iter(qpol_policy_t*);
+ qpol_iterator_t *get_alias_iter(qpol_policy_t *p) {
+ qpol_iterator_t *iter;
+ BEGIN_EXCEPTION
+ if (qpol_type_get_alias_iter(p, self, &iter)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not get type aliases");
+ }
+ END_EXCEPTION
+ fail:
+ return iter;
+ };
+ };
+%inline %{
+ qpol_type_t *qpol_type_from_void(void *x) {
+ return (qpol_type_t*)x;
+ };
+%}
+
+/* qpol role */
+typedef struct qpol_role {} qpol_role_t;
+%extend qpol_role_t {
+ qpol_role_t(qpol_policy_t *p, const char *name) {
+ const qpol_role_t *r;
+ BEGIN_EXCEPTION
+ if (qpol_policy_get_role_by_name(p, name, &r)) {
+ SWIG_exception(SWIG_RuntimeError, "Role does not exist");
+ }
+ END_EXCEPTION
+ return (qpol_role_t*)r;
+ fail:
+ return NULL;
+ };
+ ~qpol_role_t() {
+ /* no op */
+ return;
+ };
+ int get_value (qpol_policy_t *p) {
+ uint32_t v;
+ BEGIN_EXCEPTION
+ if (qpol_role_get_value(p, self, &v)) {
+ SWIG_exception(SWIG_ValueError, "Could not get role value");
+ }
+ END_EXCEPTION
+ fail:
+ return (int) v;
+ };
+ const char *get_name(qpol_policy_t *p) {
+ const char *name;
+ BEGIN_EXCEPTION
+ if (qpol_role_get_name(p, self, &name)) {
+ SWIG_exception(SWIG_ValueError, "Could not get role name");
+ }
+ END_EXCEPTION
+ return name;
+ fail:
+ return NULL;
+ };
+ %newobject get_type_iter(qpol_policy_t*);
+ qpol_iterator_t *get_type_iter(qpol_policy_t *p) {
+ qpol_iterator_t *iter;
+ BEGIN_EXCEPTION
+ if (qpol_role_get_type_iter(p, self, &iter)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not get role types");
+ }
+ END_EXCEPTION
+ fail:
+ return iter;
+ };
+ %newobject get_dominate_iter(qpol_policy_t*);
+ qpol_iterator_t *get_dominate_iter(qpol_policy_t *p) {
+ qpol_iterator_t *iter;
+ BEGIN_EXCEPTION
+ if (qpol_role_get_dominate_iter(p, self, &iter)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not get dominated roles");
+ }
+ END_EXCEPTION
+ fail:
+ return iter;
+ };
+};
+%inline %{
+ qpol_role_t *qpol_role_from_void(void *x) {
+ return (qpol_role_t*)x;
+ };
+%}
+
+/* qpol level */
+typedef struct qpol_level {} qpol_level_t;
+%extend qpol_level_t {
+ qpol_level_t(qpol_policy_t *p, const char *name) {
+ const qpol_level_t *l;
+ BEGIN_EXCEPTION
+ if (qpol_policy_get_level_by_name(p, name, &l)) {
+ SWIG_exception(SWIG_RuntimeError, "Level does not exist");
+ }
+ END_EXCEPTION
+ return (qpol_level_t*)l;
+ fail:
+ return NULL;
+ };
+ ~qpol_level_t() {
+ /* no op */
+ return;
+ };
+ int get_isalias(qpol_policy_t *p) {
+ unsigned char i;
+ BEGIN_EXCEPTION
+ if (qpol_level_get_isalias(p, self, &i)) {
+ SWIG_exception(SWIG_ValueError, "Could not determine whether level is an alias");
+ }
+ END_EXCEPTION
+ fail:
+ return (int)i;
+ };
+ int get_value(qpol_policy_t *p) {
+ uint32_t v;
+ BEGIN_EXCEPTION
+ if (qpol_level_get_value(p, self, &v)) {
+ SWIG_exception(SWIG_ValueError, "Could not get level sensitivity value");
+ }
+ END_EXCEPTION
+ fail:
+ return (int) v;
+ };
+ const char *get_name(qpol_policy_t *p) {
+ const char *name;
+ BEGIN_EXCEPTION
+ if (qpol_level_get_name(p, self, &name)) {
+ SWIG_exception(SWIG_ValueError, "Could not get level sensitivity name");
+ }
+ END_EXCEPTION
+ return name;
+ fail:
+ return NULL;
+ };
+ %newobject get_cat_iter(qpol_policy_t*);
+ qpol_iterator_t *get_cat_iter(qpol_policy_t *p) {
+ qpol_iterator_t *iter;
+ BEGIN_EXCEPTION
+ if (qpol_level_get_cat_iter(p, self, &iter)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not get level categories");
+ }
+ END_EXCEPTION
+ fail:
+ return iter;
+ };
+ %newobject get_alias_iter(qpol_policy_t*);
+ qpol_iterator_t *get_alias_iter(qpol_policy_t *p) {
+ qpol_iterator_t *iter;
+ BEGIN_EXCEPTION
+ if (qpol_level_get_alias_iter(p, self, &iter)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not get level aliases");
+ }
+ END_EXCEPTION
+ fail:
+ return iter;
+ };
+};
+%inline %{
+ qpol_level_t *qpol_level_from_void(void *x) {
+ return (qpol_level_t*)x;
+ };
+%}
+
+/* qpol cat */
+typedef struct qpol_cat {} qpol_cat_t;
+%extend qpol_cat_t {
+ qpol_cat_t(qpol_policy_t *p, const char *name) {
+ const qpol_cat_t *c;
+ BEGIN_EXCEPTION
+ if (qpol_policy_get_cat_by_name(p, name, &c)) {
+ SWIG_exception(SWIG_RuntimeError, "Category does not exist");
+ }
+ END_EXCEPTION
+ return (qpol_cat_t*)c;
+ fail:
+ return NULL;
+ };
+ ~qpol_cat_t() {
+ /* no op */
+ return;
+ };
+ int get_isalias(qpol_policy_t *p) {
+ unsigned char i;
+ BEGIN_EXCEPTION
+ if (qpol_cat_get_isalias(p, self, &i)) {
+ SWIG_exception(SWIG_ValueError, "Could not determine whether category is an alias");
+ }
+ END_EXCEPTION
+ fail:
+ return (int)i;
+ };
+ int get_value(qpol_policy_t *p) {
+ uint32_t v;
+ BEGIN_EXCEPTION
+ if (qpol_cat_get_value(p, self, &v)) {
+ SWIG_exception(SWIG_ValueError, "Could not get category value");
+ }
+ END_EXCEPTION
+ fail:
+ return (int) v;
+ };
+ const char *get_name(qpol_policy_t *p) {
+ const char *name;
+ BEGIN_EXCEPTION
+ if (qpol_cat_get_name(p, self, &name)) {
+ SWIG_exception(SWIG_ValueError, "Could not get category name");
+ }
+ END_EXCEPTION
+ return name;
+ fail:
+ return NULL;
+ };
+ %newobject get_alias_iter(qpol_policy_t*);
+ qpol_iterator_t *get_alias_iter(qpol_policy_t *p) {
+ qpol_iterator_t *iter;
+ BEGIN_EXCEPTION
+ if (qpol_cat_get_alias_iter(p, self, &iter)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not get category aliases");
+ }
+ END_EXCEPTION
+ fail:
+ return iter;
+ };
+};
+%inline %{
+ qpol_cat_t *qpol_cat_from_void(void *x) {
+ return (qpol_cat_t*)x;
+ };
+%}
+
+/* qpol mls range */
+typedef struct qpol_mls_range {} qpol_mls_range_t;
+%extend qpol_mls_range_t {
+ qpol_mls_range_t() {
+ BEGIN_EXCEPTION
+ SWIG_exception(SWIG_RuntimeError, "Cannot directly create qpol_mls_range_t objects");
+ END_EXCEPTION
+ fail:
+ return NULL;
+ }
+ ~qpol_mls_range_t() {
+ /* no op */
+ return;
+ };
+ const qpol_mls_level_t *get_high_level(qpol_policy_t *p) {
+ const qpol_mls_level_t *l;
+ BEGIN_EXCEPTION
+ if (qpol_mls_range_get_high_level(p, self, &l)) {
+ SWIG_exception(SWIG_ValueError, "Could not get range high levl");
+ }
+ END_EXCEPTION
+ fail:
+ return l;
+ };
+ const qpol_mls_level_t *get_low_level(qpol_policy_t *p) {
+ const qpol_mls_level_t *l;
+ BEGIN_EXCEPTION
+ if (qpol_mls_range_get_low_level(p, self, &l)) {
+ SWIG_exception(SWIG_ValueError, "Could not get range low levl");
+ }
+ END_EXCEPTION
+ fail:
+ return l;
+ };
+};
+%inline %{
+ qpol_mls_range_t *qpol_mls_range_from_void(void *x) {
+ return (qpol_mls_range_t*)x;
+ };
+%}
+
+/* qpol mls level */
+typedef struct qpol_mls_level {} qpol_mls_level_t;
+%extend qpol_mls_level_t {
+ qpol_mls_level_t() {
+ BEGIN_EXCEPTION
+ SWIG_exception(SWIG_RuntimeError, "Cannot directly create qpol_mls_level_t objects");
+ END_EXCEPTION
+ fail:
+ return NULL;
+ }
+ ~qpol_mls_level_t() {
+ /* no op */
+ return;
+ };
+ const char *get_sens_name(qpol_policy_t *p) {
+ const char *name;
+ BEGIN_EXCEPTION
+ if (qpol_mls_level_get_sens_name(p, self, &name)) {
+ SWIG_exception(SWIG_ValueError, "Could not get level sensitivity name");
+ }
+ END_EXCEPTION
+ fail:
+ return name;
+ };
+ %newobject get_cat_iter(qpol_policy_t*);
+ qpol_iterator_t *get_cat_iter(qpol_policy_t *p) {
+ qpol_iterator_t *iter;
+ BEGIN_EXCEPTION
+ if (qpol_mls_level_get_cat_iter(p, self, &iter)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not get level categories");
+ }
+ END_EXCEPTION
+ fail:
+ return iter;
+ };
+};
+%inline %{
+ qpol_mls_level_t *qpol_mls_level_from_void(void *x) {
+ return (qpol_mls_level_t*)x;
+ };
+%}
+
+/* qpol user */
+typedef struct qpol_user {} qpol_user_t;
+%extend qpol_user_t {
+ qpol_user_t(qpol_policy_t *p, const char *name) {
+ const qpol_user_t *u;
+ BEGIN_EXCEPTION
+ if (qpol_policy_get_user_by_name(p, name, &u)) {
+ SWIG_exception(SWIG_RuntimeError, "User does not exist");
+ }
+ END_EXCEPTION
+ return (qpol_user_t*)u;
+ fail:
+ return NULL;
+ };
+ ~qpol_user_t() {
+ /* no op */
+ return;
+ };
+ int get_value(qpol_policy_t *p) {
+ uint32_t v;
+ BEGIN_EXCEPTION
+ if (qpol_user_get_value(p, self, &v)) {
+ SWIG_exception(SWIG_ValueError, "Could not get user value");
+ }
+ END_EXCEPTION
+ fail:
+ return (int) v;
+ };
+ %newobject get_role_iter(qpol_policy_t*);
+ qpol_iterator_t *get_role_iter(qpol_policy_t *p) {
+ qpol_iterator_t *iter;
+ BEGIN_EXCEPTION
+ if (qpol_user_get_role_iter(p, self, &iter)) {
+ SWIG_exception(SWIG_MemoryError, "Out of Memory");
+ }
+ END_EXCEPTION
+ fail:
+ return iter;
+ };
+ const qpol_mls_range_t *get_range(qpol_policy_t *p) {
+ const qpol_mls_range_t *r;
+ BEGIN_EXCEPTION
+ if (qpol_user_get_range(p, self, &r)) {
+ SWIG_exception(SWIG_ValueError, "Could not get user range");
+ }
+ END_EXCEPTION
+ fail:
+ return r;
+ };
+ const char *get_name(qpol_policy_t *p) {
+ const char *name;
+ BEGIN_EXCEPTION
+ if (qpol_user_get_name(p, self, &name)) {
+ SWIG_exception(SWIG_ValueError, "Could not get user name");
+ }
+ END_EXCEPTION
+ fail:
+ return name;
+ };
+ const qpol_mls_level_t *get_dfltlevel(qpol_policy_t *p) {
+ const qpol_mls_level_t *l;
+ BEGIN_EXCEPTION
+ if (qpol_user_get_dfltlevel(p, self, &l)) {
+ SWIG_exception(SWIG_ValueError, "Could not get user default level");
+ }
+ END_EXCEPTION
+ fail:
+ return l;
+ };
+};
+%inline %{
+ qpol_user_t *qpol_user_from_void(void *x) {
+ return (qpol_user_t*)x;
+ };
+%}
+
+/* qpol bool */
+typedef struct qpol_bool {} qpol_bool_t;
+%extend qpol_bool_t {
+ qpol_bool_t(qpol_policy_t *p, const char *name) {
+ qpol_bool_t *b;
+ BEGIN_EXCEPTION
+ if (qpol_policy_get_bool_by_name(p, name, &b)) {
+ SWIG_exception(SWIG_RuntimeError, "Boolean does not exist");
+ }
+ END_EXCEPTION
+ fail:
+ return b;
+ };
+ ~qpol_bool_t() {
+ /* no op */
+ return;
+ };
+ int get_value(qpol_policy_t *p) {
+ uint32_t v;
+ BEGIN_EXCEPTION
+ if (qpol_bool_get_value(p, self, &v)) {
+ SWIG_exception(SWIG_ValueError, "Could not get boolean value");
+ }
+ END_EXCEPTION
+ fail:
+ return (int) v;
+ };
+ int get_state(qpol_policy_t *p) {
+ int s;
+ BEGIN_EXCEPTION
+ if (qpol_bool_get_state(p, self, &s)) {
+ SWIG_exception(SWIG_ValueError, "Could not get boolean state");
+ }
+ END_EXCEPTION
+ fail:
+ return s;
+ };
+ void set_state(qpol_policy_t *p, int state) {
+ BEGIN_EXCEPTION
+ if (qpol_bool_set_state(p, self, state)) {
+ SWIG_exception(SWIG_RuntimeError, "Error setting boolean state");
+ }
+ END_EXCEPTION
+ fail:
+ return;
+ };
+ void set_state_no_eval(qpol_policy_t *p, int state) {
+ BEGIN_EXCEPTION
+ if (qpol_bool_set_state_no_eval(p, self, state)) {
+ SWIG_exception(SWIG_RuntimeError, "Error setting boolean state");
+ }
+ END_EXCEPTION
+ fail:
+ return;
+ };
+ const char *get_name(qpol_policy_t *p) {
+ const char *name;
+ BEGIN_EXCEPTION
+ if (qpol_bool_get_name(p, self, &name)) {
+ SWIG_exception(SWIG_ValueError, "Could not get boolean name");
+ }
+ END_EXCEPTION
+ fail:
+ return name;
+ };
+};
+%inline %{
+ qpol_bool_t *qpol_bool_from_void(void *x) {
+ return (qpol_bool_t*)x;
+ };
+%}
+
+/* qpol context */
+typedef struct qpol_context {} qpol_context_t;
+%extend qpol_context_t {
+ qpol_context_t() {
+ BEGIN_EXCEPTION
+ SWIG_exception(SWIG_RuntimeError, "Cannot directly create qpol_context_t objects");
+ END_EXCEPTION
+ fail:
+ return NULL;
+ };
+ ~qpol_context_t() {
+ /* no op */
+ return;
+ };
+ const qpol_user_t *get_user(qpol_policy_t *p) {
+ const qpol_user_t *u;
+ BEGIN_EXCEPTION
+ if (qpol_context_get_user(p, self, &u)) {
+ SWIG_exception(SWIG_ValueError, "Could not get user from context");
+ }
+ END_EXCEPTION
+ fail:
+ return u;
+ };
+ const qpol_role_t *get_role(qpol_policy_t *p) {
+ const qpol_role_t *r;
+ BEGIN_EXCEPTION
+ if (qpol_context_get_role(p, self, &r)) {
+ SWIG_exception(SWIG_ValueError, "Could not get role from context");
+ }
+ END_EXCEPTION
+ fail:
+ return r;
+ };
+ const qpol_type_t *get_type(qpol_policy_t *p) {
+ const qpol_type_t *t;
+ BEGIN_EXCEPTION
+ if (qpol_context_get_type(p, self, &t)) {
+ SWIG_exception(SWIG_ValueError, "Could not get type from context");
+ }
+ END_EXCEPTION
+ fail:
+ return t;
+ };
+ const qpol_mls_range_t *get_range(qpol_policy_t *p) {
+ const qpol_mls_range_t *r;
+ BEGIN_EXCEPTION
+ if (qpol_context_get_range(p, self, &r)) {
+ SWIG_exception(SWIG_ValueError, "Could not get range from context");
+ }
+ END_EXCEPTION
+ fail:
+ return r;
+ };
+};
+%inline %{
+ qpol_context_t *qpol_context_from_void(void *x) {
+ return (qpol_context_t*)x;
+ };
+%}
+
+/* qpol class */
+typedef struct qpol_class {} qpol_class_t;
+%extend qpol_class_t {
+ qpol_class_t(qpol_policy_t *p, const char *name) {
+ const qpol_class_t *c;
+ BEGIN_EXCEPTION
+ if (qpol_policy_get_class_by_name(p, name, &c)) {
+ SWIG_exception(SWIG_RuntimeError, "Class does not exist");
+ }
+ END_EXCEPTION
+ fail:
+ return (qpol_class_t*)c;
+ };
+ ~qpol_class_t() {
+ /* no op */
+ return;
+ };
+ int get_value(qpol_policy_t *p) {
+ uint32_t v;
+ BEGIN_EXCEPTION
+ if (qpol_class_get_value(p, self, &v)) {
+ SWIG_exception(SWIG_ValueError, "Could not get value for class");
+ }
+ END_EXCEPTION
+ fail:
+ return (int) v;
+ };
+ const qpol_common_t *get_common(qpol_policy_t *p) {
+ const qpol_common_t *c;
+ BEGIN_EXCEPTION
+ if(qpol_class_get_common(p, self, &c)) {
+ SWIG_exception(SWIG_ValueError, "Could not get common for class");
+ }
+ END_EXCEPTION
+ fail:
+ return c;
+ };
+ %newobject get_perm_iter(qpol_policy_t*);
+ qpol_iterator_t *get_perm_iter(qpol_policy_t *p) {
+ qpol_iterator_t *iter;
+ BEGIN_EXCEPTION
+ if(qpol_class_get_perm_iter(p, self, &iter)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not get class permissions");
+ }
+ END_EXCEPTION
+ fail:
+ return iter;
+ };
+ %newobject get_constraint_iter(qpol_policy_t*);
+ qpol_iterator_t *get_constraint_iter(qpol_policy_t *p) {
+ qpol_iterator_t *iter;
+ BEGIN_EXCEPTION
+ if(qpol_class_get_constraint_iter(p, self, &iter)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not get class constraints");
+ }
+ END_EXCEPTION
+ fail:
+ return iter;
+ };
+ %newobject get_validatetrans_iter(qpol_policy_t*);
+ qpol_iterator_t *get_validatetrans_iter(qpol_policy_t *p) {
+ qpol_iterator_t *iter;
+ BEGIN_EXCEPTION
+ if(qpol_class_get_validatetrans_iter(p, self, &iter)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not get class validatetrans statements");
+ }
+ END_EXCEPTION
+ fail:
+ return iter;
+ };
+ const char *get_name(qpol_policy_t *p) {
+ const char *name;
+ BEGIN_EXCEPTION
+ if (qpol_class_get_name(p, self, &name)) {
+ SWIG_exception(SWIG_ValueError, "Could not get class name");
+ }
+ END_EXCEPTION
+ fail:
+ return name;
+ };
+};
+%inline %{
+ qpol_class_t *qpol_class_from_void(void *x) {
+ return (qpol_class_t*)x;
+ };
+%}
+
+/* qpol common */
+typedef struct qpol_common {} qpol_common_t;
+%extend qpol_common_t {
+ qpol_common_t(qpol_policy_t *p, const char *name) {
+ const qpol_common_t *c;
+ BEGIN_EXCEPTION
+ if (qpol_policy_get_common_by_name(p, name, &c)) {
+ SWIG_exception(SWIG_RuntimeError, "Common does not exist");
+ }
+ END_EXCEPTION
+ fail:
+ return (qpol_common_t*)c;
+ };
+ ~qpol_common_t() {
+ /* no op */
+ return;
+ };
+ int get_value(qpol_policy_t *p) {
+ uint32_t v;
+ BEGIN_EXCEPTION
+ if (qpol_common_get_value(p, self, &v)) {
+ SWIG_exception(SWIG_ValueError, "Could not get value for common");
+ }
+ END_EXCEPTION
+ fail:
+ return (int) v;
+ };
+ %newobject get_perm_iter(qpol_policy_t*);
+ qpol_iterator_t *get_perm_iter(qpol_policy_t *p) {
+ qpol_iterator_t *iter;
+ BEGIN_EXCEPTION
+ if(qpol_common_get_perm_iter(p, self, &iter)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not get common permissions");
+ }
+ END_EXCEPTION
+ fail:
+ return iter;
+ };
+ const char *get_name(qpol_policy_t *p) {
+ const char *name;
+ BEGIN_EXCEPTION
+ if (qpol_common_get_name(p, self, &name)) {
+ SWIG_exception(SWIG_ValueError, "Could not get common name");
+ }
+ END_EXCEPTION
+ fail:
+ return name;
+ };
+};
+%inline %{
+ qpol_common_t *qpol_common_from_void(void *x) {
+ return (qpol_common_t*)x;
+ };
+%}
+
+/* qpol fs_use */
+/* The defines QPOL_FS_USE_XATTR through QPOL_FS_USE_NONE are
+ * copied from sepol/policydb/services.h.
+ * QPOL_FS_USE_PSID is an extension to support v12 policies. */
+#ifdef SWIGJAVA /* java does not understand unsigned constants */
+#define QPOL_FS_USE_XATTR 1
+#define QPOL_FS_USE_TRANS 2
+#define QPOL_FS_USE_TASK 3
+#define QPOL_FS_USE_GENFS 4
+#define QPOL_FS_USE_NONE 5
+#define QPOL_FS_USE_PSID 6
+#else
+#define QPOL_FS_USE_XATTR 1U
+#define QPOL_FS_USE_TRANS 2U
+#define QPOL_FS_USE_TASK 3U
+#define QPOL_FS_USE_GENFS 4U
+#define QPOL_FS_USE_NONE 5U
+#define QPOL_FS_USE_PSID 6U
+#endif
+typedef struct qpol_fs_use {} qpol_fs_use_t;
+%extend qpol_fs_use_t {
+ qpol_fs_use_t(qpol_policy_t *p, const char *name) {
+ const qpol_fs_use_t *f;
+ BEGIN_EXCEPTION
+ if (qpol_policy_get_fs_use_by_name(p, name, &f)) {
+ SWIG_exception(SWIG_RuntimeError, "FS Use Statement does not exist");
+ }
+ END_EXCEPTION
+ fail:
+ return (qpol_fs_use_t*)f;
+ };
+ ~qpol_fs_use_t() {
+ /* no op */
+ return;
+ };
+ const char *get_name(qpol_policy_t *p) {
+ const char *name;
+ BEGIN_EXCEPTION
+ if (qpol_fs_use_get_name(p, self, &name)) {
+ SWIG_exception(SWIG_ValueError, "Could not get file system name");
+ }
+ END_EXCEPTION
+ fail:
+ return name;
+ };
+ int get_behavior(qpol_policy_t *p) {
+ uint32_t behav;
+ BEGIN_EXCEPTION
+ if (qpol_fs_use_get_behavior(p, self, &behav)) {
+ SWIG_exception(SWIG_ValueError, "Could not get file system labeling behavior");
+ }
+ END_EXCEPTION
+ fail:
+ return (int) behav;
+ };
+ const qpol_context_t *get_context(qpol_policy_t *p) {
+ uint32_t behav;
+ const qpol_context_t *ctx = NULL;
+ BEGIN_EXCEPTION
+ qpol_fs_use_get_behavior(p, self, &behav);
+ if (behav == QPOL_FS_USE_PSID) {
+ SWIG_exception(SWIG_TypeError, "Cannot get context for fs_use_psid statements");
+ } else if (qpol_fs_use_get_context(p, self, &ctx)) {
+ SWIG_exception(SWIG_ValueError, "Could not get file system context");
+ }
+ END_EXCEPTION
+ fail:
+ return ctx;
+ };
+};
+%inline %{
+ qpol_fs_use_t *qpol_fs_use_from_void(void *x) {
+ return (qpol_fs_use_t*)x;
+ };
+%}
+
+/* qpol genfscon */
+/* values from flask do not change */
+#ifdef SWIGJAVA /* java does not understand unsigned constants */
+#define QPOL_CLASS_ALL 0
+#define QPOL_CLASS_BLK_FILE 11
+#define QPOL_CLASS_CHR_FILE 10
+#define QPOL_CLASS_DIR 7
+#define QPOL_CLASS_FIFO_FILE 13
+#define QPOL_CLASS_FILE 6
+#define QPOL_CLASS_LNK_FILE 9
+#define QPOL_CLASS_SOCK_FILE 12
+#else
+#define QPOL_CLASS_ALL 0U
+#define QPOL_CLASS_BLK_FILE 11U
+#define QPOL_CLASS_CHR_FILE 10U
+#define QPOL_CLASS_DIR 7U
+#define QPOL_CLASS_FIFO_FILE 13U
+#define QPOL_CLASS_FILE 6U
+#define QPOL_CLASS_LNK_FILE 9U
+#define QPOL_CLASS_SOCK_FILE 12U
+#endif
+typedef struct qpol_genfscon {} qpol_genfscon_t;
+%extend qpol_genfscon_t {
+ qpol_genfscon_t(qpol_policy_t *p, const char *name, const char *path) {
+ qpol_genfscon_t *g;
+ BEGIN_EXCEPTION
+ if (qpol_policy_get_genfscon_by_name(p, name, path, &g)) {
+ SWIG_exception(SWIG_RuntimeError, "Genfscon statement does not exist");
+ }
+ END_EXCEPTION
+ fail:
+ return g;
+ };
+ ~qpol_genfscon_t() {
+ free(self);
+ };
+ const char *get_name(qpol_policy_t *p) {
+ const char *name;
+ BEGIN_EXCEPTION
+ if (qpol_genfscon_get_name(p, self, &name)) {
+ SWIG_exception(SWIG_ValueError, "Could not get file system name");
+ }
+ END_EXCEPTION
+ fail:
+ return name;
+ };
+ const char *get_path(qpol_policy_t *p) {
+ const char *path;
+ BEGIN_EXCEPTION
+ if (qpol_genfscon_get_path(p, self, &path)) {
+ SWIG_exception(SWIG_ValueError, "Could not get file system path");
+ }
+ END_EXCEPTION
+ fail:
+ return path;
+ };
+ int get_class(qpol_policy_t *p) {
+ uint32_t cls;
+ BEGIN_EXCEPTION
+ if (qpol_genfscon_get_class(p, self, &cls)) {
+ SWIG_exception(SWIG_ValueError, "Could not get genfscon statement class");
+ }
+ END_EXCEPTION
+ fail:
+ return (int) cls;
+ };
+ const qpol_context_t *get_context(qpol_policy_t *p) {
+ const qpol_context_t *ctx;
+ BEGIN_EXCEPTION
+ if (qpol_genfscon_get_context(p, self, &ctx)) {
+ SWIG_exception(SWIG_ValueError, "Could not get context for genfscon statement");
+ }
+ END_EXCEPTION
+ fail:
+ return ctx;
+ };
+};
+%inline %{
+ qpol_genfscon_t *qpol_genfscon_from_void(void *x) {
+ return (qpol_genfscon_t*)x;
+ };
+%}
+
+/* qpol isid */
+typedef struct qpol_isid {} qpol_isid_t;
+%extend qpol_isid_t {
+ qpol_isid_t(qpol_policy_t *p, const char *name) {
+ const qpol_isid_t *i;
+ BEGIN_EXCEPTION
+ if (qpol_policy_get_isid_by_name(p, name, &i)) {
+ SWIG_exception(SWIG_RuntimeError, "Isid does not exist");
+ }
+ END_EXCEPTION
+ fail:
+ return (qpol_isid_t*)i;
+ };
+ ~qpol_isid_t() {
+ /* no op */
+ return;
+ };
+ const char *get_name(qpol_policy_t *p) {
+ const char *name;
+ BEGIN_EXCEPTION
+ if (qpol_isid_get_name(p, self, &name)) {
+ SWIG_exception(SWIG_ValueError, "Could not get name for initial sid");
+ }
+ END_EXCEPTION
+ fail:
+ return name;
+ };
+ const qpol_context_t *get_context(qpol_policy_t *p) {
+ const qpol_context_t *ctx;
+ BEGIN_EXCEPTION
+ if (qpol_isid_get_context(p, self, &ctx)) {
+ SWIG_exception(SWIG_ValueError, "Could not get context for initial sid");
+ }
+ END_EXCEPTION
+ fail:
+ return ctx;
+ };
+};
+%inline %{
+ qpol_isid_t *qpol_isid_from_void(void *x) {
+ return (qpol_isid_t*)x;
+ };
+%}
+
+/* qpol netifcon */
+typedef struct qpol_netifcon {} qpol_netifcon_t;
+%extend qpol_netifcon_t {
+ qpol_netifcon_t(qpol_policy_t *p, const char *name) {
+ const qpol_netifcon_t *n;
+ BEGIN_EXCEPTION
+ if (qpol_policy_get_netifcon_by_name(p, name, &n)) {
+ SWIG_exception(SWIG_RuntimeError, "Netifcon statement does not exist");
+ }
+ END_EXCEPTION
+ fail:
+ return (qpol_netifcon_t*)n;
+ };
+ ~qpol_netifcon_t() {
+ /* no op */
+ return;
+ };
+ const char *get_name(qpol_policy_t *p) {
+ const char *name;
+ BEGIN_EXCEPTION
+ if (qpol_netifcon_get_name(p, self, &name)) {
+ SWIG_exception(SWIG_ValueError, "Could not get name for netifcon statement");
+ }
+ END_EXCEPTION
+ fail:
+ return name;
+ };
+ const qpol_context_t *get_msg_con(qpol_policy_t *p) {
+ const qpol_context_t *ctx;
+ BEGIN_EXCEPTION
+ if (qpol_netifcon_get_msg_con(p, self, &ctx)) {
+ SWIG_exception(SWIG_ValueError, "Could not get message context for netifcon statement");
+ }
+ END_EXCEPTION
+ fail:
+ return ctx;
+ };
+ const qpol_context_t *get_if_con(qpol_policy_t *p) {
+ const qpol_context_t *ctx;
+ BEGIN_EXCEPTION
+ if (qpol_netifcon_get_if_con(p, self, &ctx)) {
+ SWIG_exception(SWIG_ValueError, "Could not get interface context for netifcon statement");
+ }
+ END_EXCEPTION
+ fail:
+ return ctx;
+ };
+};
+%inline %{
+ qpol_netifcon_t *qpol_netifcon_from_void(void *x) {
+ return (qpol_netifcon_t*)x;
+ };
+%}
+
+/* qpol nodecon */
+#define QPOL_IPV4 0
+#define QPOL_IPV6 1
+typedef struct qpol_nodecon {} qpol_nodecon_t;
+%extend qpol_nodecon_t {
+ qpol_nodecon_t(qpol_policy_t *p, int addr[4], int mask[4], int protocol) {
+ uint32_t a[4], m[4];
+ qpol_nodecon_t *n;
+ BEGIN_EXCEPTION
+ a[0] = (uint32_t) addr[0]; a[1] = (uint32_t) addr[1];
+ a[2] = (uint32_t) addr[2]; a[3] = (uint32_t) addr[3];
+ m[0] = (uint32_t) mask[0]; m[1] = (uint32_t) mask[1];
+ m[2] = (uint32_t) mask[2]; m[3] = (uint32_t) mask[3];
+ if (qpol_policy_get_nodecon_by_node(p, a, m, protocol, &n)) {
+ SWIG_exception(SWIG_RuntimeError, "Nodecon statement does not exist");
+ }
+ END_EXCEPTION
+ fail:
+ return n;
+ }
+ ~qpol_nodecon_t() {
+ free(self);
+ };
+ uint32_t *get_addr(qpol_policy_t *p) {
+ uint32_t *a;
+ BEGIN_EXCEPTION
+ unsigned char proto; /* currently dropped; stores the protocol - call get_protocol() */
+ if (qpol_nodecon_get_addr(p, self, &a, &proto)) {
+ SWIG_exception(SWIG_ValueError, "Could not get address of nodecon statement");
+ }
+ END_EXCEPTION
+ fail:
+ return a;
+ };
+ uint32_t *get_mask(qpol_policy_t *p) {
+ uint32_t *m;
+ BEGIN_EXCEPTION
+ unsigned char proto; /* currently dropped; stores the protocol - call get_protocol() */
+ if (qpol_nodecon_get_mask(p, self, &m, &proto)) {
+ SWIG_exception(SWIG_ValueError, "Could not get mask of nodecon statement");
+ }
+ END_EXCEPTION
+ fail:
+ return m;
+ };
+ int get_protocol(qpol_policy_t *p) {
+ unsigned char proto;
+ BEGIN_EXCEPTION
+ if (qpol_nodecon_get_protocol(p, self, &proto)) {
+ SWIG_exception(SWIG_ValueError, "Could not get protocol for nodecon statement");
+ }
+ END_EXCEPTION
+ fail:
+ return proto;
+ };
+ const qpol_context_t *get_context(qpol_policy_t *p) {
+ const qpol_context_t *ctx;
+ BEGIN_EXCEPTION
+ if (qpol_nodecon_get_context(p, self, &ctx)) {
+ SWIG_exception(SWIG_ValueError, "Could not get context for nodecon statement");
+ }
+ END_EXCEPTION
+ fail:
+ return ctx;
+ };
+};
+%inline %{
+ qpol_nodecon_t *qpol_nodecon_from_void(void *x) {
+ return (qpol_nodecon_t*)x;
+ };
+%}
+
+/* qpol portcon */
+/* from netinet/in.h */
+#define IPPROTO_TCP 6
+#define IPPROTO_UDP 17
+typedef struct qpol_portcon {} qpol_portcon_t;
+%extend qpol_portcon_t {
+ qpol_portcon_t(qpol_policy_t *p, uint16_t low, uint16_t high, uint8_t protocol) {
+ const qpol_portcon_t *qp;
+ BEGIN_EXCEPTION
+ if (qpol_policy_get_portcon_by_port(p, low, high, protocol, &qp)) {
+ SWIG_exception(SWIG_RuntimeError, "Portcon statement does not exist");
+ }
+ END_EXCEPTION
+ fail:
+ return (qpol_portcon_t*)qp;
+ };
+ ~qpol_portcon_t() {
+ /* no op */
+ return;
+ };
+ uint16_t get_low_port(qpol_policy_t *p) {
+ uint16_t port = 0;
+ BEGIN_EXCEPTION
+ if(qpol_portcon_get_low_port(p, self, &port)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not get low port for portcon statement");
+ }
+ END_EXCEPTION
+ fail:
+ return port;
+ };
+ uint16_t get_high_port(qpol_policy_t *p) {
+ uint16_t port = 0;
+ BEGIN_EXCEPTION
+ if(qpol_portcon_get_high_port(p, self, &port)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not get high port for portcon statement");
+ }
+ END_EXCEPTION
+ fail:
+ return port;
+ };
+ uint8_t get_protocol(qpol_policy_t *p) {
+ uint8_t proto = 0;
+ BEGIN_EXCEPTION
+ if (qpol_portcon_get_protocol(p, self, &proto)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not get protocol for portcon statement");
+ }
+ END_EXCEPTION
+ fail:
+ return proto;
+ };
+ const qpol_context_t *get_context(qpol_policy_t *p) {
+ const qpol_context_t *ctx;
+ BEGIN_EXCEPTION
+ if (qpol_portcon_get_context(p, self, &ctx)) {
+ SWIG_exception(SWIG_ValueError, "Could not get context for portcon statement");
+ }
+ END_EXCEPTION
+ fail:
+ return ctx;
+ };
+}
+%inline %{
+ qpol_portcon_t *qpol_portcon_from_void(void *x) {
+ return (qpol_portcon_t*)x;
+ };
+%}
+
+/* qpol constraint */
+typedef struct qpol_constraint {} qpol_constraint_t;
+%extend qpol_constraint_t {
+ qpol_constraint_t() {
+ BEGIN_EXCEPTION
+ SWIG_exception(SWIG_RuntimeError, "Cannot directly create qpol_constraint_t objects");
+ END_EXCEPTION
+ fail:
+ return NULL;
+ };
+ ~qpol_constraint_t() {
+ free(self);
+ };
+ const qpol_class_t *get_class(qpol_policy_t *p) {
+ const qpol_class_t *cls;
+ BEGIN_EXCEPTION
+ if (qpol_constraint_get_class(p, self, &cls)) {
+ SWIG_exception(SWIG_ValueError, "Could not get class for constraint");
+ }
+ END_EXCEPTION
+ fail:
+ return cls;
+ };
+ %newobject get_perm_iter(qpol_policy_t*);
+ qpol_iterator_t *get_perm_iter(qpol_policy_t *p) {
+ qpol_iterator_t *iter;
+ BEGIN_EXCEPTION
+ if (qpol_constraint_get_perm_iter(p, self, &iter)) {
+ SWIG_exception(SWIG_MemoryError, "Out of memory");
+ }
+ END_EXCEPTION
+ fail:
+ return iter;
+ };
+ %newobject get_expr_iter(qpol_policy_t*);
+ qpol_iterator_t *get_expr_iter(qpol_policy_t *p) {
+ qpol_iterator_t *iter;
+ BEGIN_EXCEPTION
+ if (qpol_constraint_get_expr_iter(p, self, &iter)) {
+ SWIG_exception(SWIG_MemoryError, "Out of memory");
+ }
+ END_EXCEPTION
+ fail:
+ return iter;
+ };
+};
+%inline %{
+ qpol_constraint_t *qpol_constraint_from_void(void *x) {
+ return (qpol_constraint_t*)x;
+ };
+%}
+
+/* qpol validatetrans */
+typedef struct qpol_validatetrans {} qpol_validatetrans_t;
+%extend qpol_validatetrans_t {
+ qpol_validatetrans_t() {
+ BEGIN_EXCEPTION
+ SWIG_exception(SWIG_RuntimeError, "Cannot directly create qpol_validatetrans_t objects");
+ END_EXCEPTION
+ fail:
+ return NULL;
+ };
+ ~qpol_validatetrans_t() {
+ free(self);
+ };
+ const qpol_class_t *get_class(qpol_policy_t *p) {
+ const qpol_class_t *cls;
+ BEGIN_EXCEPTION
+ if (qpol_validatetrans_get_class(p, self, &cls)) {
+ SWIG_exception(SWIG_ValueError, "Could not get class for validatetrans");
+ }
+ END_EXCEPTION
+ fail:
+ return cls;
+ };
+ %newobject get_expr_iter(qpol_policy_t*);
+ qpol_iterator_t *get_expr_iter(qpol_policy_t *p) {
+ qpol_iterator_t *iter;
+ BEGIN_EXCEPTION
+ if (qpol_validatetrans_get_expr_iter(p, self, &iter)) {
+ SWIG_exception(SWIG_MemoryError, "Out of memory");
+ }
+ END_EXCEPTION
+ fail:
+ return iter;
+ };
+};
+%inline %{
+ qpol_validatetrans_t *qpol_validatetrans_from_void(void *x) {
+ return (qpol_validatetrans_t*)x;
+ };
+%}
+
+/* qpol constraint expression node */
+/* expr_type values */
+#define QPOL_CEXPR_TYPE_NOT 1
+#define QPOL_CEXPR_TYPE_AND 2
+#define QPOL_CEXPR_TYPE_OR 3
+#define QPOL_CEXPR_TYPE_ATTR 4
+#define QPOL_CEXPR_TYPE_NAMES 5
+/* symbol type values */
+#define QPOL_CEXPR_SYM_USER 1
+#define QPOL_CEXPR_SYM_ROLE 2
+#define QPOL_CEXPR_SYM_TYPE 4
+#define QPOL_CEXPR_SYM_TARGET 8
+#define QPOL_CEXPR_SYM_XTARGET 16
+#define QPOL_CEXPR_SYM_L1L2 32
+#define QPOL_CEXPR_SYM_L1H2 64
+#define QPOL_CEXPR_SYM_H1L2 128
+#define QPOL_CEXPR_SYM_H1H2 256
+#define QPOL_CEXPR_SYM_L1H1 512
+#define QPOL_CEXPR_SYM_L2H2 1024
+/* op values */
+#define QPOL_CEXPR_OP_EQ 1
+#define QPOL_CEXPR_OP_NEQ 2
+#define QPOL_CEXPR_OP_DOM 3
+#define QPOL_CEXPR_OP_DOMBY 4
+#define QPOL_CEXPR_OP_INCOMP 5
+typedef struct qpol_constraint_expr_node {} qpol_constraint_expr_node_t;
+%extend qpol_constraint_expr_node_t {
+ qpol_constraint_expr_node_t() {
+ BEGIN_EXCEPTION
+ SWIG_exception(SWIG_RuntimeError, "Cannot directly create qpol_constraint_expr_node_t objects");
+ END_EXCEPTION
+ fail:
+ return NULL;
+ };
+ ~qpol_constraint_expr_node_t() {
+ /* no op */
+ return;
+ };
+ int get_expr_type(qpol_policy_t *p) {
+ uint32_t et;
+ BEGIN_EXCEPTION
+ if (qpol_constraint_expr_node_get_expr_type(p, self, &et)) {
+ SWIG_exception(SWIG_ValueError, "Could not get expression type for node");
+ }
+ END_EXCEPTION
+ fail:
+ return (int) et;
+ };
+ int get_sym_type(qpol_policy_t *p) {
+ uint32_t st;
+ BEGIN_EXCEPTION
+ if (qpol_constraint_expr_node_get_sym_type(p, self, &st)) {
+ SWIG_exception(SWIG_ValueError, "Could not get symbol type for node");
+ }
+ END_EXCEPTION
+ fail:
+ return (int) st;
+ };
+ int get_op(qpol_policy_t *p) {
+ uint32_t op;
+ BEGIN_EXCEPTION
+ if (qpol_constraint_expr_node_get_op(p, self, &op)) {
+ SWIG_exception(SWIG_ValueError, "Could not get operator for node");
+ }
+ END_EXCEPTION
+ fail:
+ return (int) op;
+ };
+ %newobject get_names_iter(qpol_policy_t*);
+ qpol_iterator_t *get_names_iter(qpol_policy_t *p) {
+ qpol_iterator_t *iter;
+ BEGIN_EXCEPTION
+ if (qpol_constraint_expr_node_get_names_iter(p, self, &iter)) {
+ SWIG_exception(SWIG_MemoryError, "Out of memory");
+ }
+ END_EXCEPTION
+ fail:
+ return iter;
+ };
+};
+%inline %{
+ qpol_constraint_expr_node_t *qpol_constraint_expr_node_from_void(void *x) {
+ return (qpol_constraint_expr_node_t*)x;
+ };
+%}
+
+/* qpol role allow */
+typedef struct qpol_role_allow {} qpol_role_allow_t;
+%extend qpol_role_allow_t {
+ qpol_role_allow_t() {
+ BEGIN_EXCEPTION
+ SWIG_exception(SWIG_RuntimeError, "Cannot directly create qpol_role_allow_t objects");
+ END_EXCEPTION
+ fail:
+ return NULL;
+ };
+ ~qpol_role_allow_t() {
+ /* no op */
+ return;
+ };
+ const qpol_role_t *get_source_role(qpol_policy_t *p) {
+ const qpol_role_t *r;
+ BEGIN_EXCEPTION
+ if (qpol_role_allow_get_source_role(p, self, &r)) {
+ SWIG_exception(SWIG_ValueError, "Could not get source for role allow rule");
+ }
+ END_EXCEPTION
+ fail:
+ return r;
+ };
+ const qpol_role_t *get_target_role(qpol_policy_t *p) {
+ const qpol_role_t *r;
+ BEGIN_EXCEPTION
+ if (qpol_role_allow_get_target_role(p, self, &r)) {
+ SWIG_exception(SWIG_ValueError, "Could not get target for role allow rule");
+ }
+ END_EXCEPTION
+ fail:
+ return r;
+ };
+};
+%inline %{
+ qpol_role_allow_t *qpol_role_allow_from_void(void *x) {
+ return (qpol_role_allow_t*)x;
+ };
+%}
+
+/* qpol role trans */
+typedef struct qpol_role_trans {} qpol_role_trans_t;
+%extend qpol_role_trans_t {
+ qpol_role_trans_t() {
+ BEGIN_EXCEPTION
+ SWIG_exception(SWIG_RuntimeError, "Cannot directly create qpol_role_trans_t objects");
+ END_EXCEPTION
+ fail:
+ return NULL;
+ };
+ ~qpol_role_trans_t() {
+ /* no op */
+ return;
+ };
+ const qpol_role_t *get_source_role(qpol_policy_t *p) {
+ const qpol_role_t *r;
+ BEGIN_EXCEPTION
+ if (qpol_role_trans_get_source_role(p, self, &r)) {
+ SWIG_exception(SWIG_ValueError, "Could not get source for role_transition rule");
+ }
+ END_EXCEPTION
+ fail:
+ return r;
+ };
+ const qpol_type_t *get_target_type(qpol_policy_t *p) {
+ const qpol_type_t *t;
+ BEGIN_EXCEPTION
+ if (qpol_role_trans_get_target_type(p, self, &t)) {
+ SWIG_exception(SWIG_ValueError, "Could not get target for role_transition rule");
+ }
+ END_EXCEPTION
+ fail:
+ return t;
+ };
+ const qpol_role_t *get_default_role(qpol_policy_t *p) {
+ const qpol_role_t *r;
+ BEGIN_EXCEPTION
+ if (qpol_role_trans_get_default_role(p, self, &r)) {
+ SWIG_exception(SWIG_ValueError, "Could not get default for role_transition rule");
+ }
+ END_EXCEPTION
+ fail:
+ return r;
+ };
+};
+%inline %{
+ qpol_role_trans_t *qpol_role_trans_from_void(void *x) {
+ return (qpol_role_trans_t*)x;
+ };
+%}
+
+/* qpol range trans */
+typedef struct qpol_range_trans {} qpol_range_trans_t;
+%extend qpol_range_trans_t {
+ qpol_range_trans_t() {
+ BEGIN_EXCEPTION
+ SWIG_exception(SWIG_RuntimeError, "Cannot directly create qpol_range_trans_t objects");
+ END_EXCEPTION
+ fail:
+ return NULL;
+ };
+ ~qpol_range_trans_t() {
+ /* no op */
+ return;
+ };
+ const qpol_type_t *get_source_type (qpol_policy_t *p) {
+ const qpol_type_t *t;
+ BEGIN_EXCEPTION
+ if (qpol_range_trans_get_source_type(p, self, &t)) {
+ SWIG_exception(SWIG_ValueError, "Could not get source for range_transition rule");
+ }
+ END_EXCEPTION
+ fail:
+ return t;
+ };
+ const qpol_type_t *get_target_type (qpol_policy_t *p) {
+ const qpol_type_t *t;
+ BEGIN_EXCEPTION
+ if (qpol_range_trans_get_target_type(p, self, &t)) {
+ SWIG_exception(SWIG_ValueError, "Could not get target for range_transition rule"); }
+ END_EXCEPTION
+ fail:
+ return t;
+ };
+ const qpol_class_t *get_target_class(qpol_policy_t *p) {
+ const qpol_class_t *cls;
+ BEGIN_EXCEPTION
+ if (qpol_range_trans_get_target_class(p, self, &cls)) {
+ SWIG_exception(SWIG_ValueError, "Could not get class for range_transition rule"); }
+ END_EXCEPTION
+ fail:
+ return cls;
+ };
+ const qpol_mls_range_t *get_range(qpol_policy_t *p) {
+ const qpol_mls_range_t *r;
+ BEGIN_EXCEPTION
+ if (qpol_range_trans_get_range(p, self, &r)) {
+ SWIG_exception(SWIG_ValueError, "Could not get range for range_transition rule");
+ }
+ END_EXCEPTION
+ fail:
+ return r;
+ };
+};
+%inline %{
+ qpol_range_trans_t *qpol_range_trans_from_void(void *x) {
+ return (qpol_range_trans_t*)x;
+ };
+%}
+
+/* qpol av rule */
+#define QPOL_RULE_ALLOW 1
+#define QPOL_RULE_NEVERALLOW 128
+#define QPOL_RULE_AUDITALLOW 2
+#define QPOL_RULE_DONTAUDIT 4
+typedef struct qpol_avrule {} qpol_avrule_t;
+%extend qpol_avrule_t {
+ qpol_avrule_t() {
+ BEGIN_EXCEPTION
+ SWIG_exception(SWIG_RuntimeError, "Cannot directly create qpol_avrule_t objects");
+ END_EXCEPTION
+ fail:
+ return NULL;
+ };
+ ~qpol_avrule_t() {
+ /* no op */
+ return;
+ };
+ int get_rule_type(qpol_policy_t *p) {
+ uint32_t rt;
+ BEGIN_EXCEPTION
+ if (qpol_avrule_get_rule_type(p, self, &rt)) {
+ SWIG_exception(SWIG_ValueError, "Could not get rule type for av rule");
+ }
+ END_EXCEPTION
+ fail:
+ return (int) rt;
+ };
+ const qpol_type_t *get_source_type(qpol_policy_t *p) {
+ const qpol_type_t *t;
+ BEGIN_EXCEPTION
+ if (qpol_avrule_get_source_type(p, self, &t)) {
+ SWIG_exception(SWIG_ValueError, "Could not get source for av rule");
+ }
+ END_EXCEPTION
+ fail:
+ return t;
+ };
+ const qpol_type_t *get_target_type(qpol_policy_t *p) {
+ const qpol_type_t *t;
+ BEGIN_EXCEPTION
+ if (qpol_avrule_get_target_type(p, self, &t)) {
+ SWIG_exception(SWIG_ValueError, "Could not get target for av rule");
+ }
+ END_EXCEPTION
+ fail:
+ return t;
+ };
+ const qpol_class_t *get_object_class(qpol_policy_t *p) {
+ const qpol_class_t *cls;
+ BEGIN_EXCEPTION
+ if (qpol_avrule_get_object_class(p, self, &cls)) {
+ SWIG_exception(SWIG_ValueError, "Could not get class for av rule");
+ }
+ END_EXCEPTION
+ fail:
+ return cls;
+ };
+ %newobject get_perm_iter(qpol_policy_t *p);
+ qpol_iterator_t *get_perm_iter(qpol_policy_t *p) {
+ qpol_iterator_t *iter;
+ BEGIN_EXCEPTION
+ if (qpol_avrule_get_perm_iter(p, self, &iter)) {
+ SWIG_exception(SWIG_MemoryError, "Out of memory");
+ }
+ END_EXCEPTION
+ fail:
+ return iter;
+ };
+ const qpol_cond_t *get_cond(qpol_policy_t *p) {
+ const qpol_cond_t *c;
+ BEGIN_EXCEPTION
+ if (qpol_avrule_get_cond(p, self, &c)) {
+ SWIG_exception(SWIG_ValueError, "Could not get conditional for av rule");
+ }
+ END_EXCEPTION
+ fail:
+ return c;
+ };
+ int get_is_enabled(qpol_policy_t *p) {
+ uint32_t e;
+ BEGIN_EXCEPTION
+ if (qpol_avrule_get_is_enabled(p, self, &e)) {
+ SWIG_exception(SWIG_ValueError, "Could not determine if av rule is enabled");
+ }
+ END_EXCEPTION
+ fail:
+ return (int) e;
+ };
+ int get_which_list(qpol_policy_t *p) {
+ const qpol_cond_t *c;
+ uint32_t which = 0;
+ BEGIN_EXCEPTION
+ qpol_avrule_get_cond(p, self, &c);
+ if (c == NULL) {
+ SWIG_exception(SWIG_TypeError, "Rule is not conditional");
+ } else if (qpol_avrule_get_which_list(p, self, &which)) {
+ SWIG_exception(SWIG_ValueError, "Could not get conditional list for av rule");
+ }
+ END_EXCEPTION
+ fail:
+ return (int) which;
+ };
+ %newobject get_syn_avrule_iter(qpol_policy_t*);
+ qpol_iterator_t *get_syn_avrule_iter(qpol_policy_t *p) {
+ qpol_iterator_t *iter;
+ BEGIN_EXCEPTION
+ if (qpol_avrule_get_syn_avrule_iter(p, self, &iter)) {
+ SWIG_exception(SWIG_MemoryError, "Out of memory");
+ }
+ END_EXCEPTION
+ fail:
+ return iter;
+ };
+};
+%inline %{
+ qpol_avrule_t *qpol_avrule_from_void(void *x) {
+ return (qpol_avrule_t*)x;
+ };
+%}
+
+/* qpol te rule */
+#define QPOL_RULE_TYPE_TRANS 16
+#define QPOL_RULE_TYPE_CHANGE 64
+#define QPOL_RULE_TYPE_MEMBER 32
+typedef struct qpol_terule {} qpol_terule_t;
+%extend qpol_terule_t {
+ qpol_terule_t() {
+ BEGIN_EXCEPTION
+ SWIG_exception(SWIG_RuntimeError, "Cannot directly create qpol_terule_t objects");
+ END_EXCEPTION
+ fail:
+ return NULL;
+ };
+ ~qpol_terule_t() {
+ /* no op */
+ return;
+ };
+ int get_rule_type(qpol_policy_t *p) {
+ uint32_t rt;
+ BEGIN_EXCEPTION
+ if (qpol_terule_get_rule_type(p, self, &rt)) {
+ SWIG_exception(SWIG_ValueError, "Could not get rule type for te rule");
+ }
+ END_EXCEPTION
+ fail:
+ return (int) rt;
+ };
+ const qpol_type_t *get_source_type(qpol_policy_t *p) {
+ const qpol_type_t *t;
+ BEGIN_EXCEPTION
+ if (qpol_terule_get_source_type(p, self, &t)) {
+ SWIG_exception(SWIG_ValueError, "Could not get source for te rule");
+ }
+ END_EXCEPTION
+ fail:
+ return t;
+ };
+ const qpol_type_t *get_target_type(qpol_policy_t *p) {
+ const qpol_type_t *t;
+ BEGIN_EXCEPTION
+ if (qpol_terule_get_target_type(p, self, &t)) {
+ SWIG_exception(SWIG_ValueError, "Could not get target for te rule");
+ }
+ END_EXCEPTION
+ fail:
+ return t;
+ };
+ const qpol_class_t *get_object_class(qpol_policy_t *p) {
+ const qpol_class_t *cls;
+ BEGIN_EXCEPTION
+ if (qpol_terule_get_object_class(p, self, &cls)) {
+ SWIG_exception(SWIG_ValueError, "Could not get class for te rule");
+ }
+ END_EXCEPTION
+ fail:
+ return cls;
+ };
+ const qpol_type_t *get_default_type(qpol_policy_t *p) {
+ const qpol_type_t *t;
+ BEGIN_EXCEPTION
+ if (qpol_terule_get_default_type(p, self, &t)) {
+ SWIG_exception(SWIG_ValueError, "Could not get default for te rule");
+ }
+ END_EXCEPTION
+ fail:
+ return t;
+ };
+ const qpol_cond_t *get_cond(qpol_policy_t *p) {
+ const qpol_cond_t *c;
+ BEGIN_EXCEPTION
+ if (qpol_terule_get_cond(p, self, &c)) {
+ SWIG_exception(SWIG_ValueError, "Could not get conditional for te rule");
+ }
+ END_EXCEPTION
+ fail:
+ return c;
+ };
+ int get_is_enabled(qpol_policy_t *p) {
+ uint32_t e;
+ BEGIN_EXCEPTION
+ if (qpol_terule_get_is_enabled(p, self, &e)) {
+ SWIG_exception(SWIG_ValueError, "Could not determine if te rule is enabled");
+ }
+ END_EXCEPTION
+ fail:
+ return (int) e;
+ };
+ int get_which_list(qpol_policy_t *p) {
+ const qpol_cond_t *c;
+ uint32_t which = 0;
+ BEGIN_EXCEPTION
+ qpol_terule_get_cond(p, self, &c);
+ if (c == NULL) {
+ SWIG_exception(SWIG_TypeError, "Rule is not conditional");
+ } else if (qpol_terule_get_which_list(p, self, &which)) {
+ SWIG_exception(SWIG_ValueError, "Could not get conditional list for te rule");
+ }
+ END_EXCEPTION
+ fail:
+ return (int) which;
+ };
+ %newobject get_syn_terule_iter(qpol_policy_t*);
+ qpol_iterator_t *get_syn_terule_iter(qpol_policy_t *p) {
+ qpol_iterator_t *iter;
+ BEGIN_EXCEPTION
+ if (qpol_terule_get_syn_terule_iter(p, self, &iter)) {
+ SWIG_exception(SWIG_MemoryError, "Out of memory");
+ }
+ END_EXCEPTION
+ fail:
+ return iter;
+ };
+};
+%inline %{
+ qpol_terule_t *qpol_terule_from_void(void *x) {
+ return (qpol_terule_t*)x;
+ };
+%}
+
+/* qpol conditional */
+typedef struct qpol_cond {} qpol_cond_t;
+%extend qpol_cond_t {
+ qpol_cond_t() {
+ BEGIN_EXCEPTION
+ SWIG_exception(SWIG_RuntimeError, "Cannot directly create qpol_cond_t objects");
+ END_EXCEPTION
+ fail:
+ return NULL;
+ };
+ ~qpol_cond_t() {
+ /* no op */
+ return;
+ };
+ %newobject get_expr_node_iter(qpol_policy_t*);
+ qpol_iterator_t *get_expr_node_iter(qpol_policy_t *p) {
+ qpol_iterator_t *iter;
+ BEGIN_EXCEPTION
+ if (qpol_cond_get_expr_node_iter(p, self, &iter)) {
+ SWIG_exception(SWIG_MemoryError, "Out of memory");
+ }
+ END_EXCEPTION
+ fail:
+ return iter;
+ };
+ %newobject get_av_true_iter(qpol_policy_t*, int);
+ qpol_iterator_t *get_av_true_iter(qpol_policy_t *p, int rule_types) {
+ qpol_iterator_t *iter;
+ BEGIN_EXCEPTION
+ if (qpol_cond_get_av_true_iter(p, self, rule_types, &iter)) {
+ SWIG_exception(SWIG_MemoryError, "Out of memory");
+ }
+ END_EXCEPTION
+ fail:
+ return iter;
+ };
+ %newobject get_av_false_iter(qpol_policy_t*, int);
+ qpol_iterator_t *get_av_false_iter(qpol_policy_t *p, int rule_types) {
+ qpol_iterator_t *iter;
+ BEGIN_EXCEPTION
+ if (qpol_cond_get_av_false_iter(p, self, rule_types, &iter)) {
+ SWIG_exception(SWIG_MemoryError, "Out of memory");
+ }
+ END_EXCEPTION
+ fail:
+ return iter;
+ };
+ %newobject get_te_true_iter(qpol_policy_t*, int);
+ qpol_iterator_t *get_te_true_iter(qpol_policy_t *p, int rule_types) {
+ qpol_iterator_t *iter;
+ BEGIN_EXCEPTION
+ if (qpol_cond_get_te_true_iter(p, self, rule_types, &iter)) {
+ SWIG_exception(SWIG_MemoryError, "Out of memory");
+ }
+ END_EXCEPTION
+ fail:
+ return iter;
+ };
+ %newobject get_te_false_iter(qpol_policy_t*, int);
+ qpol_iterator_t *get_te_false_iter(qpol_policy_t *p, int rule_types) {
+ qpol_iterator_t *iter;
+ BEGIN_EXCEPTION
+ if (qpol_cond_get_te_false_iter(p, self, rule_types, &iter)) {
+ SWIG_exception(SWIG_MemoryError, "Out of memory");
+ }
+ END_EXCEPTION
+ fail:
+ return iter;
+ };
+ int eval(qpol_policy_t *p) {
+ uint32_t e;
+ BEGIN_EXCEPTION
+ if (qpol_cond_eval(p, self, &e)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not evaluate conditional");
+ }
+ END_EXCEPTION
+ fail:
+ return (int) e;
+ };
+};
+%inline %{
+ qpol_cond_t *qpol_cond_from_void(void *x) {
+ return (qpol_cond_t*)x;
+ };
+%}
+
+/* qpol conditional expression node */
+#define QPOL_COND_EXPR_BOOL 1 /* plain bool */
+#define QPOL_COND_EXPR_NOT 2 /* !bool */
+#define QPOL_COND_EXPR_OR 3 /* bool || bool */
+#define QPOL_COND_EXPR_AND 4 /* bool && bool */
+#define QPOL_COND_EXPR_XOR 5 /* bool ^ bool */
+#define QPOL_COND_EXPR_EQ 6 /* bool == bool */
+#define QPOL_COND_EXPR_NEQ 7 /* bool != bool */
+typedef struct qpol_cond_expr_node {} qpol_cond_expr_node_t;
+%extend qpol_cond_expr_node_t {
+ qpol_cond_expr_node_t() {
+ BEGIN_EXCEPTION
+ SWIG_exception(SWIG_RuntimeError, "Cannot directly create qpol_cond_expr_node_t objects");
+ END_EXCEPTION
+ fail:
+ return NULL;
+ };
+ ~qpol_cond_expr_node_t() {
+ /* no op */
+ return;
+ };
+ int get_expr_type(qpol_policy_t *p) {
+ uint32_t et;
+ BEGIN_EXCEPTION
+ if (qpol_cond_expr_node_get_expr_type(p, self, &et)) {
+ SWIG_exception(SWIG_ValueError, "Could not get node expression type");
+ }
+ END_EXCEPTION
+ fail:
+ return (int) et;
+ };
+ qpol_bool_t *get_bool(qpol_policy_t *p) {
+ uint32_t et;
+ qpol_bool_t *b = NULL;
+ BEGIN_EXCEPTION
+ qpol_cond_expr_node_get_expr_type(p, self, &et);
+ if (et != QPOL_COND_EXPR_BOOL) {
+ SWIG_exception(SWIG_TypeError, "Node does not contain a boolean");
+ } else if (qpol_cond_expr_node_get_bool(p, self, &b)) {
+ SWIG_exception(SWIG_ValueError, "Could not get boolean for node");
+ }
+ END_EXCEPTION
+ fail:
+ return b;
+ };
+};
+%inline %{
+ qpol_cond_expr_node_t *qpol_cond_expr_node_from_void(void *x) {
+ return (qpol_cond_expr_node_t*)x;
+ };
+%}
+
+/* qpol type set */
+typedef struct qpol_type_set {} qpol_type_set_t;
+%extend qpol_type_set_t {
+ qpol_type_set_t() {
+ BEGIN_EXCEPTION
+ SWIG_exception(SWIG_RuntimeError, "Cannot directly create qpol_type_set_t objects");
+ END_EXCEPTION
+ fail:
+ return NULL;
+ };
+ ~qpol_type_set_t() {
+ /* no op */
+ return;
+ };
+ %newobject get_included_types_iter(qpol_policy_t*);
+ qpol_iterator_t *get_included_types_iter(qpol_policy_t *p) {
+ qpol_iterator_t *iter;
+ BEGIN_EXCEPTION
+ if (qpol_type_set_get_included_types_iter(p, self, &iter)) {
+ SWIG_exception(SWIG_MemoryError, "Out of memory");
+ }
+ END_EXCEPTION
+ fail:
+ return iter;
+ };
+ %newobject get_subtracted_types_iter(qpol_policy_t*);
+ qpol_iterator_t *get_subtracted_types_iter(qpol_policy_t *p) {
+ qpol_iterator_t *iter;
+ BEGIN_EXCEPTION
+ if (qpol_type_set_get_subtracted_types_iter(p, self, &iter)) {
+ SWIG_exception(SWIG_MemoryError, "Out of memory");
+ }
+ END_EXCEPTION
+ fail:
+ return iter;
+ };
+ int get_is_star(qpol_policy_t *p) {
+ uint32_t s;
+ BEGIN_EXCEPTION
+ if (qpol_type_set_get_is_star(p, self, &s)) {
+ SWIG_exception(SWIG_ValueError, "Could not determine if type set contains star");
+ }
+ END_EXCEPTION
+ fail:
+ return (int) s;
+ };
+ int get_is_comp(qpol_policy_t *p) {
+ uint32_t c;
+ BEGIN_EXCEPTION
+ if (qpol_type_set_get_is_comp(p, self, &c)) {
+ SWIG_exception(SWIG_ValueError, "Could not determine if type set is complemented");
+ }
+ END_EXCEPTION
+ fail:
+ return (int) c;
+ };
+};
+%inline %{
+ qpol_type_set_t *qpol_type_set_from_void(void *x) {
+ return (qpol_type_set_t*)x;
+ };
+%}
+
+/* qpol syn av rule */
+typedef struct qpol_syn_avrule {} qpol_syn_avrule_t;
+%extend qpol_syn_avrule_t {
+ qpol_syn_avrule_t() {
+ BEGIN_EXCEPTION
+ SWIG_exception(SWIG_RuntimeError, "Cannot directly create qpol_syn_avrule_t objects");
+ END_EXCEPTION
+ fail:
+ return NULL;
+ };
+ ~qpol_syn_avrule_t() {
+ /* no op */
+ return;
+ };
+ int get_rule_type(qpol_policy_t *p) {
+ uint32_t rt;
+ BEGIN_EXCEPTION
+ if (qpol_syn_avrule_get_rule_type(p, self, &rt)) {
+ SWIG_exception(SWIG_ValueError, "Could not get rule type for syn av rule");
+ }
+ END_EXCEPTION
+ fail:
+ return (int) rt;
+ };
+ const qpol_type_set_t *get_source_type_set(qpol_policy_t *p) {
+ const qpol_type_set_t *ts;
+ BEGIN_EXCEPTION
+ if (qpol_syn_avrule_get_source_type_set(p, self, &ts)) {
+ SWIG_exception(SWIG_ValueError, "Could not get source type set for syn av rule");
+ }
+ END_EXCEPTION
+ fail:
+ return ts;
+ };
+ const qpol_type_set_t *get_target_type_set(qpol_policy_t *p) {
+ const qpol_type_set_t *ts;
+ BEGIN_EXCEPTION
+ if (qpol_syn_avrule_get_target_type_set(p, self, &ts)) {
+ SWIG_exception(SWIG_ValueError, "Could not get target type set for syn av rule");
+ }
+ END_EXCEPTION
+ fail:
+ return ts;
+ };
+ int get_is_target_self(qpol_policy_t *p) {
+ uint32_t i;
+ BEGIN_EXCEPTION
+ if (qpol_syn_avrule_get_is_target_self(p, self, &i)) {
+ SWIG_exception(SWIG_ValueError, "Could not determine if target is self for syn av rule");
+ }
+ END_EXCEPTION
+ fail:
+ return (int) i;
+ };
+ %newobject get_class_iter(qpol_policy_t*);
+ qpol_iterator_t *get_class_iter(qpol_policy_t *p) {
+ qpol_iterator_t *iter;
+ BEGIN_EXCEPTION
+ if (qpol_syn_avrule_get_class_iter(p, self, &iter)) {
+ SWIG_exception(SWIG_MemoryError, "Out of memory");
+ }
+ END_EXCEPTION
+ fail:
+ return iter;
+ };
+ %newobject get_perm_iter(qpol_policy_t*);
+ qpol_iterator_t *get_perm_iter(qpol_policy_t *p) {
+ qpol_iterator_t *iter;
+ BEGIN_EXCEPTION
+ if (qpol_syn_avrule_get_perm_iter(p, self, &iter)) {
+ SWIG_exception(SWIG_MemoryError, "Out of memory");
+ }
+ END_EXCEPTION
+ fail:
+ return iter;
+ };
+ long get_lineno(qpol_policy_t *p) {
+ unsigned long l;
+ BEGIN_EXCEPTION
+ if (qpol_syn_avrule_get_lineno(p, self, &l)) {
+ SWIG_exception(SWIG_ValueError, "Could not get line number for syn av rule");
+ }
+ END_EXCEPTION
+ fail:
+ return (long)l;
+ };
+ const qpol_cond_t *get_cond(qpol_policy_t *p) {
+ const qpol_cond_t *c;
+ BEGIN_EXCEPTION
+ if (qpol_syn_avrule_get_cond(p, self, &c)) {
+ SWIG_exception(SWIG_ValueError, "Could not get conditional for syn av rule");
+ }
+ END_EXCEPTION
+ fail:
+ return c;
+ };
+ int get_is_enabled(qpol_policy_t *p) {
+ uint32_t e;
+ BEGIN_EXCEPTION
+ if (qpol_syn_avrule_get_is_enabled(p, self, &e)) {
+ SWIG_exception(SWIG_ValueError, "Could not determine if syn av rule is enabled");
+ }
+ END_EXCEPTION
+ fail:
+ return e;
+ };
+};
+%inline %{
+ qpol_syn_avrule_t *qpol_syn_avrule_from_void(void *x) {
+ return (qpol_syn_avrule_t*)x;
+ };
+%}
+
+/* qpol syn te rule */
+typedef struct qpol_syn_terule {} qpol_syn_terule_t;
+%extend qpol_syn_terule_t {
+ qpol_syn_terule_t() {
+ BEGIN_EXCEPTION
+ SWIG_exception(SWIG_RuntimeError, "Cannot directly create qpol_syn_terule_t objects");
+ END_EXCEPTION
+ fail:
+ return NULL;
+ };
+ ~qpol_syn_terule_t() {
+ /* no op */
+ return;
+ };
+ int get_rule_type(qpol_policy_t *p) {
+ uint32_t rt;
+ BEGIN_EXCEPTION
+ if (qpol_syn_terule_get_rule_type(p, self, &rt)) {
+ SWIG_exception(SWIG_ValueError, "Could not get rule type for syn te rule");
+ }
+ END_EXCEPTION
+ fail:
+ return rt;
+ };
+ const qpol_type_set_t *get_source_type_set(qpol_policy_t *p) {
+ const qpol_type_set_t *ts;
+ BEGIN_EXCEPTION
+ if (qpol_syn_terule_get_source_type_set(p, self, &ts)) {
+ SWIG_exception(SWIG_ValueError, "Could not get source type set for syn te rule");
+ }
+ END_EXCEPTION
+ fail:
+ return ts;
+ };
+ const qpol_type_set_t *get_target_type_set(qpol_policy_t *p) {
+ const qpol_type_set_t *ts;
+ BEGIN_EXCEPTION
+ if (qpol_syn_terule_get_target_type_set(p, self, &ts)) {
+ SWIG_exception(SWIG_ValueError, "Could not get target type set for syn te rule");
+ }
+ END_EXCEPTION
+ fail:
+ return ts;
+ };
+ %newobject get_class_iter(qpol_policy_t*);
+ qpol_iterator_t *get_class_iter(qpol_policy_t *p) {
+ qpol_iterator_t *iter;
+ BEGIN_EXCEPTION
+ if (qpol_syn_terule_get_class_iter(p, self, &iter)) {
+ SWIG_exception(SWIG_MemoryError, "Out of memory");
+ }
+ END_EXCEPTION
+ fail:
+ return iter;
+ };
+ const qpol_type_t *get_default_type(qpol_policy_t *p) {
+ const qpol_type_t *t;
+ BEGIN_EXCEPTION
+ if (qpol_syn_terule_get_default_type(p, self, &t)) {
+ SWIG_exception(SWIG_ValueError, "Could not get default type for syn te rule");
+ }
+ END_EXCEPTION
+ fail:
+ return t;
+ };
+ long get_lineno(qpol_policy_t *p) {
+ unsigned long l;
+ BEGIN_EXCEPTION
+ if (qpol_syn_terule_get_lineno(p, self, &l)) {
+ SWIG_exception(SWIG_ValueError, "Could not get line number for syn te rule");
+ }
+ END_EXCEPTION
+ fail:
+ return (long)l;
+ };
+ const qpol_cond_t *get_cond(qpol_policy_t *p) {
+ const qpol_cond_t *c;
+ BEGIN_EXCEPTION
+ if (qpol_syn_terule_get_cond(p, self, &c)) {
+ SWIG_exception(SWIG_ValueError, "Could not get conditional for syn te rule");
+ }
+ END_EXCEPTION
+ fail:
+ return c;
+ };
+ int get_is_enabled(qpol_policy_t *p) {
+ uint32_t e;
+ BEGIN_EXCEPTION
+ if (qpol_syn_terule_get_is_enabled(p, self, &e)) {
+ SWIG_exception(SWIG_ValueError, "Could not determine if syn te rule is enabled");
+ }
+ END_EXCEPTION
+ fail:
+ return (int) e;
+ };
+};
+%inline %{
+ qpol_syn_terule_t *qpol_syn_terule_from_void(void *x) {
+ return (qpol_syn_terule_t*)x;
+ };
+%}
+// vim:ft=c noexpandtab
diff --git a/libqpol/swig/tcl/Makefile.am b/libqpol/swig/tcl/Makefile.am
new file mode 100644
index 0000000..f65d301
--- /dev/null
+++ b/libqpol/swig/tcl/Makefile.am
@@ -0,0 +1,35 @@
+wrappedso_DATA = libtqpol.so.@libqpol_version@
+wrappedso_SONAME = @libqpol_tswig_soname@
+short_name = libtqpol.so
+wrappedsodir = $(libdir)/setools/qpol
+
+package_SCRIPTS = pkgIndex.tcl
+packagedir = $(wrappedsodir)
+
+dist_noinst_DATA = $(srcdir)/../qpol.i
+BUILT_SOURCES = qpol_wrap.c
+
+AM_CFLAGS = @DEBUGCFLAGS@ @WARNCFLAGS@ @PROFILECFLAGS@ @SELINUX_CFLAGS@ \
+ -I$(top_builddir) -fpic \
+ -I$(top_srcdir)/libqpol/include
+AM_LDFLAGS = @DEBUGLDFLAGS@ @WARNLDFLAGS@ @PROFILELDFLAGS@ @QPOL_LIB_FLAG@ @TCL_LIB_SPEC@
+
+$(BUILT_SOURCES): $(dist_noinst_DATA) $(DEPENDENCIES)
+ $(SWIG) $(SWIG_TCL_OPT) -pkgversion @libqpol_version@ -o $@ $<
+
+$(wrappedso_DATA): $(BUILT_SOURCES)
+ $(CC) -shared -o $@ $^ $(AM_CFLAGS) $(CFLAGS) $(SWIG_TCL_CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -Wl,-soname,$(wrappedso_SONAME)
+ $(LN_S) -f $@ $(wrappedso_SONAME)
+ $(LN_S) -f $@ $(short_name)
+
+libdirs = $(top_builddir)/libqpol/src
+
+$(package_SCRIPTS): $(wrappedso_DATA)
+ echo "pkg_mkIndex . $^" | LD_LIBRARY_PATH=$(top_builddir)/libqpol/src $(TCLSH_PROG)
+ chmod 644 $@
+ $(mkdir_p) qpol
+ cp $(wrappedso_DATA) $@ qpol
+
+MOSTLYCLEANFILES = $(BUILT_SOURCES) $(wrappedso_DATA) $(wrappedso_SONAME) $(short_name) $(package_DATA) qpol/$(wrappedso_DATA) qpol/$(package_SCRIPTS)
+
+CLEANFILES = $(package_SCRIPTS)
diff --git a/libqpol/tests/Makefile.am b/libqpol/tests/Makefile.am
new file mode 100644
index 0000000..bad0b82
--- /dev/null
+++ b/libqpol/tests/Makefile.am
@@ -0,0 +1,17 @@
+TESTS = libqpol-tests
+check_PROGRAMS = libqpol-tests
+
+libqpol_tests_SOURCES = \
+ capabilities-tests.c capabilities-tests.h \
+ iterators-tests.c iterators-tests.h \
+ policy-features-tests.c policy-features-tests.h \
+ libqpol-tests.c
+
+AM_CFLAGS = @DEBUGCFLAGS@ @WARNCFLAGS@ @PROFILECFLAGS@ @SELINUX_CFLAGS@ \
+ @QPOL_CFLAGS@
+
+AM_LDFLAGS = @DEBUGLDFLAGS@ @WARNLDFLAGS@ @PROFILELDFLAGS@
+
+LDADD = @SELINUX_LIB_FLAG@ @QPOL_LIB_FLAG@ @CUNIT_LIB_FLAG@
+
+libqpol_tests_DEPENDENCIES = ../src/libqpol.so
diff --git a/libqpol/tests/capabilities-tests.c b/libqpol/tests/capabilities-tests.c
new file mode 100644
index 0000000..c428c71
--- /dev/null
+++ b/libqpol/tests/capabilities-tests.c
@@ -0,0 +1,542 @@
+/**
+ * @file
+ *
+ * Test policy loading capabilities that were introduced in SETools
+ * 3.2.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2007-2008 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
+ */
+
+#include <config.h>
+
+#include <CUnit/CUnit.h>
+#include <qpol/policy.h>
+
+#include <stdbool.h>
+
+#define POLICY_ROOT TEST_POLICIES "/policy-versions"
+
+struct capability_answer
+{
+ const char *policy_name;
+ int policy_type;
+ unsigned int policy_version;
+ bool has_attributes;
+ bool has_syn_rules;
+ bool has_line_numbers;
+ bool has_conditionals;
+ bool has_mls;
+ bool has_polcaps;
+ bool has_source;
+ bool has_modules;
+ char *enforcing_type, *permissive_type;
+};
+
+static void capability_test(const struct capability_answer *ca)
+{
+ qpol_policy_t *q = NULL;
+ int policy_type = qpol_policy_open_from_file(ca->policy_name, &q, NULL, NULL, QPOL_POLICY_OPTION_NO_NEVERALLOWS);
+ CU_ASSERT_FATAL(policy_type >= 0);
+ CU_ASSERT_EQUAL(policy_type, ca->policy_type);
+
+ unsigned policy_version;
+ int retval;
+ retval = qpol_policy_get_policy_version(q, &policy_version);
+ CU_ASSERT_EQUAL_FATAL(retval, 0);
+ CU_ASSERT_EQUAL(policy_version, ca->policy_version);
+
+ bool cap;
+
+ cap = (bool) qpol_policy_has_capability(q, QPOL_CAP_ATTRIB_NAMES);
+ CU_ASSERT_EQUAL(cap, ca->has_attributes);
+
+ cap = (bool) qpol_policy_has_capability(q, QPOL_CAP_SYN_RULES);
+ CU_ASSERT_EQUAL(cap, ca->has_syn_rules);
+
+ cap = (bool) qpol_policy_has_capability(q, QPOL_CAP_LINE_NUMBERS);
+ CU_ASSERT_EQUAL(cap, ca->has_line_numbers);
+
+ cap = (bool) qpol_policy_has_capability(q, QPOL_CAP_CONDITIONALS);
+ CU_ASSERT_EQUAL(cap, ca->has_conditionals);
+
+ cap = (bool) qpol_policy_has_capability(q, QPOL_CAP_MLS);
+ CU_ASSERT_EQUAL(cap, ca->has_mls);
+
+ cap = (bool) qpol_policy_has_capability(q, QPOL_CAP_POLCAPS);
+ CU_ASSERT_EQUAL(cap, ca->has_polcaps);
+
+ cap = (bool) qpol_policy_has_capability(q, QPOL_CAP_SOURCE);
+ CU_ASSERT_EQUAL(cap, ca->has_source);
+
+ cap = (bool) qpol_policy_has_capability(q, QPOL_CAP_MODULES);
+ CU_ASSERT_EQUAL(cap, ca->has_modules);
+
+ unsigned char ispermissive;
+ const qpol_type_t *type;
+
+ if (ca->enforcing_type != NULL) {
+ retval = qpol_policy_get_type_by_name(q, ca->enforcing_type, &type);
+ CU_ASSERT(retval == 0 && type != NULL);
+ retval = qpol_type_get_ispermissive(q, type, &ispermissive);
+ CU_ASSERT(retval == 0 && ispermissive == 0);
+ }
+ if (ca->permissive_type != NULL) {
+ retval = qpol_policy_get_type_by_name(q, ca->permissive_type, &type);
+ CU_ASSERT(retval == 0 && type != NULL);
+ retval = qpol_type_get_ispermissive(q, type, &ispermissive);
+ CU_ASSERT(retval == 0 && ispermissive == 1);
+ }
+
+ qpol_policy_destroy(&q);
+}
+
+static void capability_v12_source(void)
+{
+ struct capability_answer cap = {
+ POLICY_ROOT "/policy-12.conf",
+ QPOL_POLICY_KERNEL_SOURCE, // policy type
+ 12U, // policy version
+ true, // has attributes
+ true, // has syntactic rules
+ true, // has line numbers
+ false, // has conditionals
+ false, // has mls
+ false, // has policy capabilities
+ true, // has source
+ false, // has modules
+ "fs_t", NULL // enforcing / permissive types
+ };
+ capability_test(&cap);
+}
+
+static void capability_v15_source(void)
+{
+ struct capability_answer cap = {
+ POLICY_ROOT "/policy-15.conf",
+ QPOL_POLICY_KERNEL_SOURCE, // policy type
+ 15U, // policy version
+ true, // has attributes
+ true, // has syntactic rules
+ true, // has line numbers
+ false, // has conditionals
+ false, // has mls
+ false, // has policy capabilities
+ true, // has source
+ false, // has modules
+ "fs_t", NULL // enforcing / permissive types
+ };
+ capability_test(&cap);
+}
+
+static void capability_v15_binary(void)
+{
+ struct capability_answer cap = {
+ POLICY_ROOT "/policy.15",
+ QPOL_POLICY_KERNEL_BINARY, // policy type
+ 15U, // policy version
+ false, // has attributes
+ false, // has syntactic rules
+ false, // has line numbers
+ false, // has conditionals
+ false, // has mls
+ false, // has policy capabilities
+ false, // has source
+ false, // has modules
+ "fs_t", NULL // enforcing / permissive types
+ };
+ capability_test(&cap);
+}
+
+static void capability_v16_source(void)
+{
+ struct capability_answer cap = {
+ POLICY_ROOT "/policy-16.conf",
+ QPOL_POLICY_KERNEL_SOURCE, // policy type
+ 16U, // policy version
+ true, // has attributes
+ true, // has syntactic rules
+ true, // has line numbers
+ true, // has conditionals
+ false, // has mls
+ false, // has policy capabilities
+ true, // has source
+ false, // has modules
+ "fs_t", NULL // enforcing / permissive types
+ };
+ capability_test(&cap);
+}
+
+static void capability_v16_binary(void)
+{
+ struct capability_answer cap = {
+ POLICY_ROOT "/policy.16",
+ QPOL_POLICY_KERNEL_BINARY, // policy type
+ 16U, // policy version
+ false, // has attributes
+ false, // has syntactic rules
+ false, // has line numbers
+ true, // has conditionals
+ false, // has mls
+ false, // has policy capabilities
+ false, // has source
+ false, // has modules
+ "fs_t", NULL // enforcing / permissive types
+ };
+ capability_test(&cap);
+}
+
+static void capability_v17_source(void)
+{
+ struct capability_answer cap = {
+ POLICY_ROOT "/policy-17.conf",
+ QPOL_POLICY_KERNEL_SOURCE, // policy type
+ 17U, // policy version
+ true, // has attributes
+ true, // has syntactic rules
+ true, // has line numbers
+ true, // has conditionals
+ false, // has mls
+ false, // has policy capabilities
+ true, // has source
+ false, // has modules
+ "fs_t", NULL // enforcing / permissive types
+ };
+ capability_test(&cap);
+}
+
+static void capability_v17_binary(void)
+{
+ struct capability_answer cap = {
+ POLICY_ROOT "/policy.17",
+ QPOL_POLICY_KERNEL_BINARY, // policy type
+ 17U, // policy version
+ false, // has attributes
+ false, // has syntactic rules
+ false, // has line numbers
+ true, // has conditionals
+ false, // has mls
+ false, // has policy capabilities
+ false, // has source
+ false, // has modules
+ "fs_t", NULL // enforcing / permissive types
+ };
+ capability_test(&cap);
+}
+
+static void capability_v18_source(void)
+{
+ struct capability_answer cap = {
+ POLICY_ROOT "/policy-18.conf",
+ QPOL_POLICY_KERNEL_SOURCE, // policy type
+ 18U, // policy version
+ true, // has attributes
+ true, // has syntactic rules
+ true, // has line numbers
+ true, // has conditionals
+ false, // has mls
+ false, // has policy capabilities
+ true, // has source
+ false, // has modules
+ "wing_t", NULL // enforcing / permissive types
+ };
+ capability_test(&cap);
+}
+
+static void capability_v18_binary(void)
+{
+ struct capability_answer cap = {
+ POLICY_ROOT "/policy.18",
+ QPOL_POLICY_KERNEL_BINARY, // policy type
+ 18U, // policy version
+ false, // has attributes
+ false, // has syntactic rules
+ false, // has line numbers
+ true, // has conditionals
+ false, // has mls
+ false, // has policy capabilities
+ false, // has source
+ false, // has modules
+ "wing_t", NULL // enforcing / permissive types
+ };
+ capability_test(&cap);
+}
+
+static void capability_v19_binary(void)
+{
+ struct capability_answer cap = {
+ POLICY_ROOT "/policy.19",
+ QPOL_POLICY_KERNEL_BINARY, // policy type
+ 19U, // policy version
+ false, // has attributes
+ false, // has syntactic rules
+ false, // has line numbers
+ true, // has conditionals
+ false, // has mls
+ false, // has policy capabilities
+ false, // has source
+ false, // has modules
+ "wing_t", NULL // enforcing / permissive types
+ };
+ capability_test(&cap);
+}
+
+static void capability_v19_binary_mls(void)
+{
+ struct capability_answer cap = {
+ POLICY_ROOT "/policy-mls.19",
+ QPOL_POLICY_KERNEL_BINARY, // policy type
+ 19U, // policy version
+ false, // has attributes
+ false, // has syntactic rules
+ false, // has line numbers
+ true, // has conditionals
+ true, // has mls
+ false, // has policy capabilities
+ false, // has source
+ false, // has modules
+ "root_t", NULL // enforcing / permissive types
+ };
+ capability_test(&cap);
+}
+
+static void capability_v20_binary(void)
+{
+ struct capability_answer cap = {
+ POLICY_ROOT "/policy.20",
+ QPOL_POLICY_KERNEL_BINARY, // policy type
+ 20U, // policy version
+ false, // has attributes
+ false, // has syntactic rules
+ false, // has line numbers
+ true, // has conditionals
+ false, // has mls
+ false, // has policy capabilities
+ false, // has source
+ false, // has modules
+ "wing_t", NULL // enforcing / permissive types
+ };
+ capability_test(&cap);
+}
+
+static void capability_v20_binary_mls(void)
+{
+ struct capability_answer cap = {
+ POLICY_ROOT "/policy-mls.20",
+ QPOL_POLICY_KERNEL_BINARY, // policy type
+ 20U, // policy version
+ false, // has attributes
+ false, // has syntactic rules
+ false, // has line numbers
+ true, // has conditionals
+ true, // has mls
+ false, // has policy capabilities
+ false, // has source
+ false, // has modules
+ "root_t", NULL // enforcing / permissive types
+ };
+ capability_test(&cap);
+}
+
+static void capability_v21_source(void)
+{
+ struct capability_answer cap = {
+ POLICY_ROOT "/policy-mls-21.conf",
+ QPOL_POLICY_KERNEL_SOURCE, // policy type
+ 21U, // policy version
+ true, // has attributes
+ true, // has syntactic rules
+ true, // has line numbers
+ true, // has conditionals
+ true, // has mls
+ false, // has policy capabilities
+ true, // has source
+ false, // has modules
+ "root_t", NULL // enforcing / permissive types
+ };
+ capability_test(&cap);
+}
+
+static void capability_v21_binary(void)
+{
+ struct capability_answer cap = {
+ POLICY_ROOT "/policy-mls.21",
+ QPOL_POLICY_KERNEL_BINARY, // policy type
+ 21U, // policy version
+ false, // has attributes
+ false, // has syntactic rules
+ false, // has line numbers
+ true, // has conditionals
+ true, // has mls
+ false, // has policy capabilities
+ false, // has source
+ false, // has modules
+ "root_t", NULL // enforcing / permissive types
+ };
+ capability_test(&cap);
+}
+
+static void capability_v22_source(void)
+{
+ struct capability_answer cap = {
+ POLICY_ROOT "/policy-mls-22.conf",
+ QPOL_POLICY_KERNEL_SOURCE, // policy type
+ 22U, // policy version
+ true, // has attributes
+ true, // has syntactic rules
+ true, // has line numbers
+ true, // has conditionals
+ true, // has mls
+ true, // has policy capabilities
+ true, // has source
+ false, // has modules
+ "root_t", NULL // enforcing / permissive types
+ };
+ capability_test(&cap);
+}
+
+static void capability_v22_binary(void)
+{
+ struct capability_answer cap = {
+ POLICY_ROOT "/policy-mls.22",
+ QPOL_POLICY_KERNEL_BINARY, // policy type
+ 22U, // policy version
+ false, // has attributes
+ false, // has syntactic rules
+ false, // has line numbers
+ true, // has conditionals
+ true, // has mls
+ true, // has policy capabilities
+ false, // has source
+ false, // has modules
+ "root_t", NULL // enforcing / permissive types
+ };
+ capability_test(&cap);
+}
+
+static void capability_v23_source(void)
+{
+ struct capability_answer cap = {
+ POLICY_ROOT "/policy-mls-23.conf",
+ QPOL_POLICY_KERNEL_SOURCE, // policy type
+ 23U, // policy version
+ true, // has attributes
+ true, // has syntactic rules
+ true, // has line numbers
+ true, // has conditionals
+ true, // has mls
+ true, // has policy capabilities
+ true, // has source
+ false, // has modules
+ "root_t", "system_t" // enforcing / permissive types
+ };
+ capability_test(&cap);
+}
+
+static void capability_v23_binary(void)
+{
+ struct capability_answer cap = {
+ POLICY_ROOT "/policy-mls.23",
+ QPOL_POLICY_KERNEL_BINARY, // policy type
+ 23U, // policy version
+ false, // has attributes
+ false, // has syntactic rules
+ false, // has line numbers
+ true, // has conditionals
+ true, // has mls
+ true, // has policy capabilities
+ false, // has source
+ false, // has modules
+ "root_t", "system_t" // enforcing / permissive types
+ };
+ capability_test(&cap);
+}
+
+static void capability_modv6_base_binary(void)
+{
+ struct capability_answer cap = {
+ POLICY_ROOT "/base-6.pp",
+ QPOL_POLICY_MODULE_BINARY, // policy type
+ 6U, // policy version
+ true, // has attributes
+ true, // has syntactic rules
+ false, // has line numbers
+ true, // has conditionals
+ true, // has mls
+ false, // has policy capabilities
+ false, // has source
+ true, // has modules
+ "root_t", NULL // enforcing / permissive types
+ };
+ capability_test(&cap);
+}
+
+static void capability_modv8_base_binary(void)
+{
+ struct capability_answer cap = {
+ POLICY_ROOT "/base-8.pp",
+ QPOL_POLICY_MODULE_BINARY, // policy type
+ 8U, // policy version
+ true, // has attributes
+ true, // has syntactic rules
+ false, // has line numbers
+ true, // has conditionals
+ true, // has mls
+ true, // has policy capabilities
+ false, // has source
+ true, // has modules
+ "root_t", "system_t" // enforcing / permissive types
+ };
+ capability_test(&cap);
+}
+
+CU_TestInfo capabilities_tests[] = {
+ {"v12, source", capability_v12_source},
+ {"v15, source", capability_v15_source},
+ {"v15, binary", capability_v15_binary},
+ {"v16, source", capability_v16_source},
+ {"v16, binary", capability_v16_binary},
+ {"v17, source", capability_v17_source},
+ {"v17, binary", capability_v17_binary},
+ {"v18, source", capability_v18_source},
+ {"v18, binary", capability_v18_binary},
+ {"v19, binary", capability_v19_binary},
+ {"v19, binary mls", capability_v19_binary_mls},
+ {"v20, binary", capability_v20_binary},
+ {"v20, binary mls", capability_v20_binary_mls},
+ {"v21, source", capability_v21_source},
+ {"v21, binary", capability_v21_binary},
+ {"v22, source", capability_v22_source},
+ {"v22, binary", capability_v22_binary},
+ {"v23, source", capability_v23_source},
+ {"v23, binary", capability_v23_binary},
+ {"mod v6, base binary", capability_modv6_base_binary},
+ {"mod v8, base binary", capability_modv8_base_binary},
+ CU_TEST_INFO_NULL
+};
+
+int capabilities_init()
+{
+ return 0;
+}
+
+int capabilities_cleanup()
+{
+ return 0;
+}
diff --git a/libqpol/tests/capabilities-tests.h b/libqpol/tests/capabilities-tests.h
new file mode 100644
index 0000000..b305b77
--- /dev/null
+++ b/libqpol/tests/capabilities-tests.h
@@ -0,0 +1,35 @@
+/**
+ * @file
+ *
+ * Declarations for libqpol capabilities tests.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 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
+ */
+
+#ifndef CAPABILITES_TESTS_H
+#define CAPABILITES_TESTS_H
+
+#include <CUnit/CUnit.h>
+
+extern CU_TestInfo capabilities_tests[];
+extern int capabilities_init();
+extern int capabilities_cleanup();
+
+#endif
diff --git a/libqpol/tests/iterators-tests.c b/libqpol/tests/iterators-tests.c
new file mode 100644
index 0000000..384f878
--- /dev/null
+++ b/libqpol/tests/iterators-tests.c
@@ -0,0 +1,87 @@
+/**
+ * @file
+ *
+ * Test qpol iterators.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 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
+ */
+
+#include <config.h>
+
+#include <CUnit/CUnit.h>
+#include <qpol/policy.h>
+#include <stdio.h>
+
+#define SOURCE_POLICY TEST_POLICIES "/snapshots/fc4_targeted.policy.conf"
+
+static qpol_policy_t *qp = NULL;
+
+static void iterators_alias(void)
+{
+ qpol_iterator_t *iter = NULL;
+ CU_ASSERT_FATAL(qpol_policy_get_type_iter(qp, &iter) == 0);
+ while (!qpol_iterator_end(iter)) {
+ void *v;
+ CU_ASSERT_FATAL(qpol_iterator_get_item(iter, &v) == 0);
+ qpol_type_t *type = (qpol_type_t *) v;
+
+ qpol_iterator_t *alias_iter = NULL;
+ size_t alias_size;
+ unsigned char isalias = 0;
+ CU_ASSERT_FATAL(qpol_type_get_isalias(qp, type, &isalias) == 0);
+ CU_ASSERT_FATAL(qpol_type_get_alias_iter(qp, type, &alias_iter) == 0);
+ CU_ASSERT_FATAL(qpol_iterator_get_size(alias_iter, &alias_size) == 0);
+
+ if (alias_size > 0) {
+ /* isalias could be 0 or 1, depending upon if
+ type is a primary or an alias */
+ CU_ASSERT(!qpol_iterator_end(alias_iter));
+ } else {
+ /* impossible for isalias to be true if the
+ alias iterator is empty */
+ CU_ASSERT(!isalias && qpol_iterator_end(alias_iter));
+ }
+
+ qpol_iterator_destroy(&alias_iter);
+ CU_ASSERT_FATAL(qpol_iterator_next(iter) == 0);
+ }
+ qpol_iterator_destroy(&iter);
+}
+
+CU_TestInfo iterators_tests[] = {
+ {"alias iterator", iterators_alias}
+ ,
+ CU_TEST_INFO_NULL
+};
+
+int iterators_init()
+{
+ int policy_type = qpol_policy_open_from_file(SOURCE_POLICY, &qp, NULL, NULL, QPOL_POLICY_OPTION_NO_RULES);
+ if (policy_type < 0) {
+ return 1;
+ }
+ return 0;
+}
+
+int iterators_cleanup()
+{
+ qpol_policy_destroy(&qp);
+ return 0;
+}
diff --git a/libqpol/tests/iterators-tests.h b/libqpol/tests/iterators-tests.h
new file mode 100644
index 0000000..275f3a2
--- /dev/null
+++ b/libqpol/tests/iterators-tests.h
@@ -0,0 +1,35 @@
+/**
+ * @file
+ *
+ * Declarations for libqpol iterator tests.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 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
+ */
+
+#ifndef ITERATORS_TESTS_H
+#define ITERATORS_TESTS_H
+
+#include <CUnit/CUnit.h>
+
+extern CU_TestInfo iterators_tests[];
+extern int iterators_init();
+extern int iterators_cleanup();
+
+#endif
diff --git a/libqpol/tests/libqpol-tests.c b/libqpol/tests/libqpol-tests.c
new file mode 100644
index 0000000..eda58d6
--- /dev/null
+++ b/libqpol/tests/libqpol-tests.c
@@ -0,0 +1,57 @@
+/**
+ * @file
+ *
+ * CUnit testing framework for libqpol.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 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
+ */
+
+#include <config.h>
+
+#include <CUnit/CUnit.h>
+#include <CUnit/Basic.h>
+
+#include "capabilities-tests.h"
+#include "iterators-tests.h"
+#include "policy-features-tests.h"
+
+int main(void)
+{
+ if (CU_initialize_registry() != CUE_SUCCESS) {
+ return CU_get_error();
+ }
+
+ CU_SuiteInfo suites[] = {
+ {"Capabilities", capabilities_init, capabilities_cleanup, capabilities_tests}
+ ,
+ {"Iterators", iterators_init, iterators_cleanup, iterators_tests}
+ ,
+ {"Policy Featurens", policy_features_init, policy_features_cleanup, policy_features_tests}
+ ,
+ CU_SUITE_INFO_NULL
+ };
+
+ CU_register_suites(suites);
+ CU_basic_set_mode(CU_BRM_VERBOSE);
+ CU_basic_run_tests();
+ unsigned int num_failures = CU_get_number_of_failure_records();
+ CU_cleanup_registry();
+ return (int)num_failures;
+}
diff --git a/libqpol/tests/policy-features-tests.c b/libqpol/tests/policy-features-tests.c
new file mode 100644
index 0000000..915dbaf
--- /dev/null
+++ b/libqpol/tests/policy-features-tests.c
@@ -0,0 +1,145 @@
+/**
+ * @file
+ *
+ * Test qpol loading of special types of policies.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 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
+ */
+
+#include <config.h>
+
+#include <CUnit/CUnit.h>
+#include <qpol/policy.h>
+#include "../src/qpol_internal.h"
+#include <stdio.h>
+
+#define BROKEN_ALIAS_POLICY TEST_POLICIES "/setools-3.3/policy-features/broken-alias-mod.21"
+#define NOT_BROKEN_ALIAS_POLICY TEST_POLICIES "/setools-3.3/policy-features/not-broken-alias-mod.21"
+#define NOGENFS_POLICY TEST_POLICIES "/setools-3.3/policy-features/nogenfscon-policy.21"
+
+static void policy_features_alias_count(void *varg, const qpol_policy_t * policy
+ __attribute__ ((unused)), int level, const char *fmt, va_list va_args)
+{
+ if (level == QPOL_MSG_WARN) {
+ int *num_removed_aliases = (int *)varg;
+ (*num_removed_aliases)++;
+ } else if (level == QPOL_MSG_ERR) {
+ fprintf(stderr, "ERROR: ");
+ vfprintf(stderr, fmt, va_args);
+ fprintf(stderr, "\n");
+ }
+}
+
+/**
+ * If a module has any disabled aliases, test that libqpol removed them.
+ */
+static void policy_features_invalid_alias(void)
+{
+ qpol_policy_t *qp = NULL;
+ int policy_features_removed_aliases = 0;
+ void *v;
+ unsigned char isalias = 0;
+ const char *name;
+
+ int policy_type = qpol_policy_open_from_file(NOT_BROKEN_ALIAS_POLICY, &qp, policy_features_alias_count,
+ &policy_features_removed_aliases, QPOL_POLICY_OPTION_NO_RULES);
+ CU_ASSERT_FATAL(policy_type == QPOL_POLICY_KERNEL_BINARY);
+ CU_ASSERT(policy_features_removed_aliases == 0)
+
+ qpol_iterator_t *iter = NULL;
+ CU_ASSERT_FATAL(qpol_policy_get_type_iter(qp, &iter) == 0);
+ while (!qpol_iterator_end(iter)) {
+ CU_ASSERT_FATAL(qpol_iterator_get_item(iter, &v) == 0);
+ qpol_type_t *type = (qpol_type_t *) v;
+ CU_ASSERT_FATAL(qpol_type_get_isalias(qp, type, &isalias) == 0);
+ if (isalias) {
+ CU_ASSERT_FATAL(qpol_type_get_name(qp, type, &name) == 0);
+ CU_ASSERT_STRING_EQUAL(name, "fs_t");
+ }
+ CU_ASSERT_FATAL(qpol_iterator_next(iter) == 0);
+ }
+ qpol_iterator_destroy(&iter);
+ qpol_policy_destroy(&qp);
+
+ policy_features_removed_aliases = 0;
+ policy_type =
+ qpol_policy_open_from_file(BROKEN_ALIAS_POLICY, &qp, policy_features_alias_count, &policy_features_removed_aliases,
+ QPOL_POLICY_OPTION_NO_RULES);
+ CU_ASSERT_FATAL(policy_type == QPOL_POLICY_KERNEL_BINARY);
+ CU_ASSERT(policy_features_removed_aliases == 1)
+
+ CU_ASSERT_FATAL(qpol_policy_get_type_iter(qp, &iter) == 0);
+ while (!qpol_iterator_end(iter)) {
+ CU_ASSERT_FATAL(qpol_iterator_get_item(iter, &v) == 0);
+ qpol_type_t *type = (qpol_type_t *) v;
+ CU_ASSERT_FATAL(qpol_type_get_isalias(qp, type, &isalias) == 0);
+ CU_ASSERT(isalias == 0);
+ CU_ASSERT_FATAL(qpol_iterator_next(iter) == 0);
+ }
+ qpol_iterator_destroy(&iter);
+ qpol_policy_destroy(&qp);
+}
+
+/** Test that getting an iterator of genfscon statements does not
+ * fail if there are no genfscon statements. */
+static void policy_features_nogenfscon_iter(void)
+{
+ qpol_policy_t *qp = NULL;
+
+ /* open a policy with no genfscon statements */
+ int policy_type = qpol_policy_open_from_file(NOGENFS_POLICY, &qp, NULL, NULL, QPOL_POLICY_OPTION_NO_RULES);
+ CU_ASSERT_FATAL(policy_type == QPOL_POLICY_KERNEL_BINARY);
+
+ qpol_iterator_t *iter = NULL;
+
+ /* iterator should be safe to request but should be at end */
+ CU_ASSERT_FATAL(qpol_policy_get_genfscon_iter(qp, &iter) == 0);
+ CU_ASSERT(qpol_iterator_end(iter));
+ qpol_iterator_destroy(&iter);
+ qpol_policy_destroy(&qp);
+
+ /* open a policy with genfscon statements */
+ policy_type = qpol_policy_open_from_file(NOT_BROKEN_ALIAS_POLICY, &qp, NULL, NULL, QPOL_POLICY_OPTION_NO_RULES);
+ CU_ASSERT_FATAL(policy_type == QPOL_POLICY_KERNEL_BINARY);
+
+ /* iterator should be safe to request and not at end */
+ CU_ASSERT_FATAL(qpol_policy_get_genfscon_iter(qp, &iter) == 0);
+ CU_ASSERT(!qpol_iterator_end(iter));
+ qpol_iterator_destroy(&iter);
+ qpol_policy_destroy(&qp);
+}
+
+CU_TestInfo policy_features_tests[] = {
+ {"invalid alias", policy_features_invalid_alias}
+ ,
+ {"No genfscon", policy_features_nogenfscon_iter}
+ ,
+ CU_TEST_INFO_NULL
+};
+
+int policy_features_init()
+{
+ return 0;
+}
+
+int policy_features_cleanup()
+{
+ return 0;
+}
diff --git a/libqpol/tests/policy-features-tests.h b/libqpol/tests/policy-features-tests.h
new file mode 100644
index 0000000..71463dd
--- /dev/null
+++ b/libqpol/tests/policy-features-tests.h
@@ -0,0 +1,35 @@
+/**
+ * @file
+ *
+ * Declarations for libqpol tests for reading special types of policies.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 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
+ */
+
+#ifndef POLICY_FEATURES_TESTS_H
+#define POLICY_FEATURES_TESTS_H
+
+#include <CUnit/CUnit.h>
+
+extern CU_TestInfo policy_features_tests[];
+extern int policy_features_init();
+extern int policy_features_cleanup();
+
+#endif