diff options
Diffstat (limited to 'libqpol')
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 |