From 287f507657e162bc09b5c186bbd580901fbc942a Mon Sep 17 00:00:00 2001 From: Dan Walsh Date: Tue, 20 Sep 2011 15:47:28 -0400 Subject: [PATCH 6/6] Changes to support named file_trans rules --- libapol/include/apol/ftrule-query.h | 198 +++++++++++++++++++ libapol/include/apol/policy-query.h | 1 + libapol/src/Makefile.am | 1 + libapol/src/ftrule-query.c | 363 +++++++++++++++++++++++++++++++++++ libapol/src/libapol.map | 1 + libqpol/include/qpol/ftrule_query.h | 116 +++++++++++ libqpol/include/qpol/policy.h | 1 + libqpol/src/Makefile.am | 1 + libqpol/src/ftrule_query.c | 277 ++++++++++++++++++++++++++ libqpol/src/libqpol.map | 1 + libqpol/src/module_compiler.c | 12 ++ libqpol/src/policy_define.c | 186 ++++++++++++++++++- libqpol/src/policy_parse.y | 13 +- libqpol/src/policy_scan.l | 1 + secmds/sesearch.c | 101 ++++++++++ 15 files changed, 1270 insertions(+), 3 deletions(-) create mode 100644 libapol/include/apol/ftrule-query.h create mode 100644 libapol/src/ftrule-query.c create mode 100644 libqpol/include/qpol/ftrule_query.h create mode 100644 libqpol/src/ftrule_query.c diff --git a/libapol/include/apol/ftrule-query.h b/libapol/include/apol/ftrule-query.h new file mode 100644 index 0000000..119c52f --- /dev/null +++ b/libapol/include/apol/ftrule-query.h @@ -0,0 +1,198 @@ +/** + * @file + * + * Routines to query filename_transition rules of a + * policy. + * + * @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 APOL_FILENAMERULE_QUERY_H +#define APOL_FILENAMERULE_QUERY_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "policy.h" +#include "vector.h" +#include + + typedef struct apol_filename_trans_query apol_filename_trans_query_t; + + +/******************** filename_transition queries ********************/ + +/** + * Execute a query against all filename_transition rules within the + * policy. + * + * @param p Policy within which to look up filename_transition rules. + * @param r Structure containing parameters for query. If this is + * NULL then return all filename_transition rules. + * @param v Reference to a vector of qpol_filename_trans_t. The vector + * will be allocated by this function. The caller must call + * apol_vector_destroy() afterwards. This will be set to NULL upon no + * results or upon error. + * + * @return 0 on success (including none found), negative on error. + */ + extern int apol_filename_trans_get_by_query(const apol_policy_t * p, const apol_filename_trans_query_t * r, apol_vector_t ** v); + +/** + * Allocate and return a new filename trans query structure. All fields + * are initialized, such that running this blank query results in + * returning all filename_transitions within the policy. The caller must + * call apol_filename_trans_query_destroy() upon the return value + * afterwards. + * + * @return An initialized filename trans query structure, or NULL upon + * error. + */ + extern apol_filename_trans_query_t *apol_filename_trans_query_create(void); + +/** + * Deallocate all memory associated with the referenced filename trans + * query, and then set it to NULL. This function does nothing if the + * query is already NULL. + * + * @param r Reference to a filename trans query structure to destroy. + */ + extern void apol_filename_trans_query_destroy(apol_filename_trans_query_t ** r); + +/** + * Set a filename_trans query to return rules whose source symbol matches + * symbol. Symbol may be a type or attribute; if it is an alias then + * the query will convert it to its primary prior to searching. If + * is_indirect is non-zero then the search will be done indirectly. + * If the symbol is a type, then the query matches rules with one of + * the type's attributes. If the symbol is an attribute, then it + * matches rule with any of the attribute's types. + * + * @param p Policy handler, to report errors. + * @param t TE rule query to set. + * @param symbol Limit query to rules with this symbol as their + * source, or NULL to unset this field. + * @param is_indirect If non-zero, perform indirect matching. + * + * @return 0 on success, negative on error. + */ + extern int apol_filename_trans_query_set_source(const apol_policy_t * p, apol_filename_trans_query_t * t, const char *symbol, + int is_indirect); + +/** + * Set a filename trans query to return rules with a particular target + * symbol. Symbol may be a type or attribute; if it is an alias then + * the query will convert it to its primary prior to searching. If + * is_indirect is non-zero then the search will be done indirectly. + * If the symbol is a type, then the query matches rules with one of + * the type's attributes. If the symbol is an attribute, then it + * matches rule with any of the attribute's types. + * + * @param p Policy handler, to report errors. + * @param r Role trans query to set. + * @param symbol Limit query to rules with this type or attribute as + * their target, or NULL to unset this field. + * @param is_indirect If non-zero, perform indirect matching. + * + * @return 0 on success, negative on error. + */ + extern int apol_filename_trans_query_set_target(const apol_policy_t * p, apol_filename_trans_query_t * r, const char *symbol, + int is_indirect); + +/** + * Set a filename trans query to return rules with a particular default + * filename. This field is ignored if + * apol_filename_trans_query_set_source_any() is set to non-zero. + * + * @param p Policy handler, to report errors. + * @param r Role trans query to set. + * @param filename Limit query to rules with this filename as their default, or + * NULL to unset this field. + * + * @return 0 on success, negative on error. + */ + extern int apol_filename_trans_query_set_default(const apol_policy_t * p, apol_filename_trans_query_t * r, const char *filename); + +/** + * Set at filename_trans query to return rules with this object (non-common) + * class. If more than one class are appended to the query, the + * rule's class must be one of those appended. (I.e., the rule's + * class must be a member of the query's classes.) Pass a NULL to + * clear all classes. Note that this performs straight string + * comparison, ignoring the regex flag. + + * + * @param p Policy handler, to report errors. + * @param t TE rule query to set. + * @param obj_class Name of object class to add to search set. + * + * @return 0 on success, negative on error. + */ + extern int apol_filename_trans_query_append_class(const apol_policy_t * p, apol_filename_trans_query_t * t, const char *obj_class); + +/** + * Set a filename trans query to treat the source filename as any. That is, + * use the same symbol for either source or default of a + * filename_transition rule. This flag does nothing if the source filename is + * not set. Note that a filename_transition's target is a type, so thus + * this flag does not affect its searching. + * + * @param p Policy handler, to report errors. + * @param r Role trans query to set. + * @param is_any Non-zero to use source symbol for source or default + * field, 0 to keep source as only source. + * + * @return Always 0. + */ + extern int apol_filename_trans_query_set_source_any(const apol_policy_t * p, apol_filename_trans_query_t * r, int is_any); + +/** + * Set a filename trans query to use regular expression searching for + * source, target, and default fields. Strings will be treated as + * regexes instead of literals. For the target type, matching will + * occur against the type name or any of its aliases. + * + * @param p Policy handler, to report errors. + * @param r Role trans query to set. + * @param is_regex Non-zero to enable regex searching, 0 to disable. + * + * @return Always 0. + */ + extern int apol_filename_trans_query_set_regex(const apol_policy_t * p, apol_filename_trans_query_t * r, int is_regex); + +/** + * Render a filename_transition rule to a string. + * + * @param policy Policy handler, to report errors. + * @param rule The rule to render. + * + * @return A newly malloc()'d string representation of the rule, or NULL on + * failure; if the call fails, errno will be set. The caller is responsible + * for calling free() on the returned string. + */ + extern char *apol_filename_trans_render(const apol_policy_t * policy, const qpol_filename_trans_t * rule); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libapol/include/apol/policy-query.h b/libapol/include/apol/policy-query.h index 315f70e..665e4cb 100644 --- a/libapol/include/apol/policy-query.h +++ b/libapol/include/apol/policy-query.h @@ -71,6 +71,7 @@ extern "C" #include "terule-query.h" #include "condrule-query.h" #include "rbacrule-query.h" +#include "ftrule-query.h" #include "range_trans-query.h" #include "constraint-query.h" diff --git a/libapol/src/Makefile.am b/libapol/src/Makefile.am index 3fa4f06..baaa4f6 100644 --- a/libapol/src/Makefile.am +++ b/libapol/src/Makefile.am @@ -40,6 +40,7 @@ libapol_a_SOURCES = \ render.c \ role-query.c \ terule-query.c \ + ftrule-query.c \ type-query.c \ types-relation-analysis.c \ user-query.c \ diff --git a/libapol/src/ftrule-query.c b/libapol/src/ftrule-query.c new file mode 100644 index 0000000..dc248de --- /dev/null +++ b/libapol/src/ftrule-query.c @@ -0,0 +1,363 @@ +/** + * @file + * + * Provides a way for setools to make queries about type enforcement + * filename_transs within a policy. The caller obtains a query object, fills in + * its parameters, and then runs the query; it obtains a vector of + * results. Searches are conjunctive -- all fields of the search + * query must match for a datum to be added to the results query. + * + * @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 "policy-query-internal.h" + +#include +#include + +struct apol_filename_trans_query +{ + char *source, *target, *default_type, *name; + apol_vector_t *classes; + unsigned int flags; +}; + + +/******************** filename_transition queries ********************/ + +int apol_filename_trans_get_by_query(const apol_policy_t * p, const apol_filename_trans_query_t * t, apol_vector_t ** v) +{ + apol_vector_t *source_list = NULL, *target_list = NULL, *class_list = NULL, *default_list = NULL; + int retval = -1, source_as_any = 0, is_regex = 0, append_filename_trans; + char *bool_name = NULL; + *v = NULL; + unsigned int flags = 0; + qpol_iterator_t *iter = NULL, *type_iter = NULL; + + if (t != NULL) { + flags = t->flags; + is_regex = t->flags & APOL_QUERY_REGEX; + if (t->source != NULL && + (source_list = + apol_query_create_candidate_type_list(p, t->source, is_regex, + t->flags & APOL_QUERY_SOURCE_INDIRECT, + ((t->flags & (APOL_QUERY_SOURCE_TYPE | APOL_QUERY_SOURCE_ATTRIBUTE)) / + APOL_QUERY_SOURCE_TYPE))) == NULL) { + goto cleanup; + } + + if ((t->flags & APOL_QUERY_SOURCE_AS_ANY) && t->source != NULL) { + default_list = target_list = source_list; + source_as_any = 1; + } else { + if (t->target != NULL && + (target_list = + apol_query_create_candidate_type_list(p, t->target, is_regex, + t->flags & APOL_QUERY_TARGET_INDIRECT, + ((t-> + flags & (APOL_QUERY_TARGET_TYPE | APOL_QUERY_TARGET_ATTRIBUTE)) + / APOL_QUERY_TARGET_TYPE))) == NULL) { + goto cleanup; + } + if (t->default_type != NULL && + (default_list = + apol_query_create_candidate_type_list(p, t->default_type, is_regex, 0, + APOL_QUERY_SYMBOL_IS_TYPE)) == NULL) { + goto cleanup; + } + } + if (t->classes != NULL && + apol_vector_get_size(t->classes) > 0 && + (class_list = apol_query_create_candidate_class_list(p, t->classes)) == NULL) { + goto cleanup; + } + } + + if (qpol_policy_get_filename_trans_iter(p->p, &iter) < 0) { + return -1; + } + + if ((*v = apol_vector_create(NULL)) == NULL) { + ERR(p, "%s", strerror(errno)); + goto cleanup; + } + + for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) { + qpol_filename_trans_t *filename_trans; + if (qpol_iterator_get_item(iter, (void **)&filename_trans) < 0) { + goto cleanup; + } + int match_source = 0, match_target = 0, match_default = 0, match_bool = 0; + size_t i; + + if (source_list == NULL) { + match_source = 1; + } else { + const qpol_type_t *source_type; + if (qpol_filename_trans_get_source_type(p->p, filename_trans, &source_type) < 0) { + goto cleanup; + } + if (apol_vector_get_index(source_list, source_type, NULL, NULL, &i) == 0) { + match_source = 1; + } + } + + /* if source did not match, but treating source symbol + * as any field, then delay rejecting this filename_trans until + * the target and default have been checked */ + if (!source_as_any && !match_source) { + continue; + } + + if (target_list == NULL || (source_as_any && match_source)) { + match_target = 1; + } else { + const qpol_type_t *target_type; + if (qpol_filename_trans_get_target_type(p->p, filename_trans, &target_type) < 0) { + goto cleanup; + } + if (apol_vector_get_index(target_list, target_type, NULL, NULL, &i) == 0) { + match_target = 1; + } + } + + if (!source_as_any && !match_target) { + continue; + } + + if (default_list == NULL || (source_as_any && match_source) || (source_as_any && match_target)) { + match_default = 1; + } else { + const qpol_type_t *default_type; + if (qpol_filename_trans_get_default_type(p->p, filename_trans, &default_type) < 0) { + goto cleanup; + } + if (apol_vector_get_index(default_list, default_type, NULL, NULL, &i) == 0) { + match_default = 1; + } + } + + if (!source_as_any && !match_default) { + continue; + } + /* at least one thing must match if source_as_any was given */ + if (source_as_any && (!match_source && !match_target && !match_default)) { + continue; + } + + if (class_list != NULL) { + const qpol_class_t *obj_class; + if (qpol_filename_trans_get_object_class(p->p, filename_trans, &obj_class) < 0) { + goto cleanup; + } + if (apol_vector_get_index(class_list, obj_class, NULL, NULL, &i) < 0) { + continue; + } + } + + if (apol_vector_append(*v, filename_trans)) { + ERR(p, "%s", strerror(ENOMEM)); + goto cleanup; + } + } + + retval = 0; + cleanup: + if (retval != 0) { + apol_vector_destroy(v); + } + apol_vector_destroy(&source_list); + if (!source_as_any) { + apol_vector_destroy(&target_list); + apol_vector_destroy(&default_list); + } + apol_vector_destroy(&class_list); + return retval; +} + +apol_filename_trans_query_t *apol_filename_trans_query_create(void) +{ + apol_filename_trans_query_t *t = calloc(1, sizeof(apol_filename_trans_query_t)); + if (t != NULL) { + t->flags = + (APOL_QUERY_SOURCE_TYPE | APOL_QUERY_SOURCE_ATTRIBUTE | APOL_QUERY_TARGET_TYPE | + APOL_QUERY_TARGET_ATTRIBUTE); + } + return t; +} + +void apol_filename_trans_query_destroy(apol_filename_trans_query_t ** r) +{ + if (r != NULL && *r != NULL) { + free((*r)->source); + free((*r)->target); + free((*r)->default_type); + free((*r)->name); + free(*r); + *r = NULL; + } +} + +int apol_filename_trans_query_set_source(const apol_policy_t * p, apol_filename_trans_query_t * t, const char *filename, int is_indirect) +{ + apol_query_set_flag(p, &t->flags, is_indirect, APOL_QUERY_TARGET_INDIRECT); + return apol_query_set(p, &t->source, NULL, filename); +} + +int apol_filename_trans_query_set_target(const apol_policy_t * p, apol_filename_trans_query_t * t, const char *type, int is_indirect) +{ + apol_query_set_flag(p, &t->flags, is_indirect, APOL_QUERY_TARGET_INDIRECT); + return apol_query_set(p, &t->target, NULL, type); +} + +int apol_filename_trans_query_set_default(const apol_policy_t * p, apol_filename_trans_query_t * t, const char *symbol) +{ + return apol_query_set(p, &t->default_type, NULL, symbol); +} + +int apol_filename_trans_query_append_class(const apol_policy_t * p, apol_filename_trans_query_t * t, const char *obj_class) +{ + char *s = NULL; + if (obj_class == NULL) { + apol_vector_destroy(&t->classes); + } else if ((s = strdup(obj_class)) == NULL || (t->classes == NULL && (t->classes = apol_vector_create(free)) == NULL) + || apol_vector_append(t->classes, s) < 0) { + ERR(p, "%s", strerror(errno)); + free(s); + return -1; + } + return 0; +} + +int apol_filename_trans_query_set_name(const apol_policy_t * p, apol_filename_trans_query_t * t, const char *filename) +{ + return apol_query_set(p, &t->name, NULL, filename); +} + +int apol_filename_trans_query_set_source_any(const apol_policy_t * p, apol_filename_trans_query_t * t, int is_any) +{ + return apol_query_set_flag(p, &t->flags, is_any, APOL_QUERY_SOURCE_AS_ANY); +} + +int apol_filename_trans_query_set_regex(const apol_policy_t * p, apol_filename_trans_query_t * t, int is_regex) +{ + return apol_query_set_regex(p, &t->flags, is_regex); +} + +char *apol_filename_trans_render(const apol_policy_t * policy, const qpol_filename_trans_t * filename_trans) +{ + char *tmp = NULL; + const char *tmp_name = NULL; + const char *filename_trans_type_str; + int error = 0; + size_t tmp_sz = 0; + uint32_t filename_trans_type = 0; + const qpol_type_t *type = NULL; + const qpol_class_t *obj_class = NULL; + + if (!policy || !filename_trans) { + ERR(policy, "%s", strerror(EINVAL)); + errno = EINVAL; + return NULL; + } + + /* source type */ + if (qpol_filename_trans_get_source_type(policy->p, filename_trans, &type)) { + error = errno; + goto err; + } + if (qpol_type_get_name(policy->p, type, &tmp_name)) { + error = errno; + goto err; + } + if (apol_str_appendf(&tmp, &tmp_sz, "transition_type %s ", tmp_name)) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto err; + } + + /* target type */ + if (qpol_filename_trans_get_target_type(policy->p, filename_trans, &type)) { + error = errno; + goto err; + } + if (qpol_type_get_name(policy->p, type, &tmp_name)) { + error = errno; + goto err; + } + if (apol_str_appendf(&tmp, &tmp_sz, "%s : ", tmp_name)) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto err; + } + + /* object class */ + if (qpol_filename_trans_get_object_class(policy->p, filename_trans, &obj_class)) { + error = errno; + goto err; + } + if (qpol_class_get_name(policy->p, obj_class, &tmp_name)) { + error = errno; + goto err; + } + if (apol_str_appendf(&tmp, &tmp_sz, "%s ", tmp_name)) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto err; + } + + /* default type */ + if (qpol_filename_trans_get_default_type(policy->p, filename_trans, &type)) { + error = errno; + goto err; + } + if (qpol_type_get_name(policy->p, type, &tmp_name)) { + error = errno; + goto err; + } + if (apol_str_appendf(&tmp, &tmp_sz, "%s", tmp_name)) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto err; + } + + if (qpol_filename_trans_get_filename(policy->p, filename_trans, &tmp_name)) { + error = errno; + goto err; + } + + if (apol_str_appendf(&tmp, &tmp_sz, " %s", tmp_name)) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto err; + } + + if (apol_str_appendf(&tmp, &tmp_sz, ";")) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto err; + } + return tmp; + + err: + free(tmp); + errno = error; + return NULL; +} diff --git a/libapol/src/libapol.map b/libapol/src/libapol.map index 4894374..7657a2d 100644 --- a/libapol/src/libapol.map +++ b/libapol/src/libapol.map @@ -34,6 +34,7 @@ VERS_4.0{ apol_protocol_to_str; apol_qpol_context_render; apol_range_trans_*; + apol_filename_trans_*; apol_relabel_*; apol_role_*; apol_role_allow_*; diff --git a/libqpol/include/qpol/ftrule_query.h b/libqpol/include/qpol/ftrule_query.h new file mode 100644 index 0000000..1f533a4 --- /dev/null +++ b/libqpol/include/qpol/ftrule_query.h @@ -0,0 +1,116 @@ +/** + * @file + * Defines public interface for iterating over FTRULE 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_FTRULERULE_QUERY +#define QPOL_FTRULERULE_QUERY + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include +#include + + typedef struct qpol_filename_trans qpol_filename_trans_t; + +/** + * Get an iterator over all filename transition rules in the policy. + * @param policy Policy from which to create the iterator. + * @param iter Iterator over items of type qpol_filename_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_filename_trans_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter); + +/** + * Get the source type from a filename transition rule. + * @param policy The 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. + * @return 0 on success and < 0 on failure; if the call fails, + * errno will be set and *source will be NULL. + */ + extern int qpol_filename_trans_get_source_type(const qpol_policy_t * policy, const qpol_filename_trans_t * rule, + const qpol_type_t ** source); + +/** + * Get the target type from a filename 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_filename_trans_get_target_type(const qpol_policy_t * policy, const qpol_filename_trans_t * rule, + const qpol_type_t ** target); + +/** + * 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_filename_trans_get_default_type(const qpol_policy_t * policy, const qpol_filename_trans_t * rule, + const qpol_type_t ** dflt); + +/** + * 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_filename_trans_get_object_class(const qpol_policy_t * policy, const qpol_filename_trans_t * rule, + const qpol_class_t ** obj_class); + +/** + * Get the transition filename type from a type rule. + * @param policy Policy from which the rule comes. + * @param rule The rule from which to get the transition filename. + * @param target Pointer in which to store the transition filename. + * 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_filename_trans_get_filename(const qpol_policy_t * policy, const qpol_filename_trans_t * rule, + const char ** name); + +#ifdef __cplusplus +} +#endif + +#endif /* QPOL_FTRULERULE_QUERY */ diff --git a/libqpol/include/qpol/policy.h b/libqpol/include/qpol/policy.h index ae4ea08..bf85718 100644 --- a/libqpol/include/qpol/policy.h +++ b/libqpol/include/qpol/policy.h @@ -55,6 +55,7 @@ extern "C" #include #include #include +#include #include #include #include diff --git a/libqpol/src/Makefile.am b/libqpol/src/Makefile.am index 34d87a6..0889a61 100644 --- a/libqpol/src/Makefile.am +++ b/libqpol/src/Makefile.am @@ -48,6 +48,7 @@ libqpol_a_SOURCES = \ syn_rule_internal.h \ syn_rule_query.c \ terule_query.c \ + ftrule_query.c \ type_query.c \ user_query.c \ util.c \ diff --git a/libqpol/src/ftrule_query.c b/libqpol/src/ftrule_query.c new file mode 100644 index 0000000..d6db848 --- /dev/null +++ b/libqpol/src/ftrule_query.c @@ -0,0 +1,277 @@ +/** + * @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 +#include +#include +#include +#include "iterator_internal.h" +#include "qpol_internal.h" +#include + +typedef struct filename_trans_state +{ + filename_trans_t *head; + filename_trans_t *cur; +} filename_trans_state_t; + +static int filename_trans_state_end(const qpol_iterator_t * iter) +{ + filename_trans_state_t *fts = NULL; + + if (!iter || !(fts = qpol_iterator_state(iter))) { + errno = EINVAL; + return STATUS_ERR; + } + + return fts->cur ? 0 : 1; +} + +static void *filename_trans_state_get_cur(const qpol_iterator_t * iter) +{ + filename_trans_state_t *fts = NULL; + const policydb_t *db = NULL; + + if (!iter || !(fts = qpol_iterator_state(iter)) || !(db = qpol_iterator_policy(iter)) || filename_trans_state_end(iter)) { + errno = EINVAL; + return NULL; + } + + return fts->cur; +} + +static int filename_trans_state_next(qpol_iterator_t * iter) +{ + filename_trans_state_t *fts = NULL; + const policydb_t *db = NULL; + + if (!iter || !(fts = qpol_iterator_state(iter)) || !(db = qpol_iterator_policy(iter))) { + errno = EINVAL; + return STATUS_ERR; + } + + if (filename_trans_state_end(iter)) { + errno = ERANGE; + return STATUS_ERR; + } + + fts->cur = fts->cur->next; + + return STATUS_SUCCESS; +} + +static size_t filename_trans_state_size(const qpol_iterator_t * iter) +{ + filename_trans_state_t *fts = NULL; + const policydb_t *db = NULL; + filename_trans_t *tmp = NULL; + size_t count = 0; + + if (!iter || !(fts = qpol_iterator_state(iter)) || !(db = qpol_iterator_policy(iter))) { + errno = EINVAL; + return STATUS_ERR; + } + + for (tmp = fts->head; tmp; tmp = tmp->next) + count++; + + return count; +} + +int qpol_policy_get_filename_trans_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter) +{ + policydb_t *db = NULL; + filename_trans_state_t *fts = 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; + + fts = calloc(1, sizeof(filename_trans_state_t)); + if (!fts) { + /* errno set by calloc */ + ERR(policy, "%s", strerror(errno)); + return STATUS_ERR; + } + fts->head = fts->cur = db->filename_trans; + + if (qpol_iterator_create + (policy, (void *)fts, filename_trans_state_get_cur, filename_trans_state_next, filename_trans_state_end, filename_trans_state_size, + free, iter)) { + error = errno; + free(fts); + errno = error; + return STATUS_ERR; + } + + return STATUS_SUCCESS; +} + +int qpol_filename_trans_get_source_type(const qpol_policy_t * policy, const qpol_filename_trans_t * rule, const qpol_type_t ** source) +{ + policydb_t *db = NULL; + filename_trans_t *ft = NULL; + + if (source) { + *source = NULL; + } + + if (!policy || !rule || !source) { + ERR(policy, "%s", strerror(EINVAL)); + errno = EINVAL; + return STATUS_ERR; + } + + db = &policy->p->p; + ft = (filename_trans_t *) rule; + + *source = (qpol_type_t *) db->type_val_to_struct[ft->stype - 1]; + + return STATUS_SUCCESS; +} + +int qpol_filename_trans_get_target_type(const qpol_policy_t * policy, const qpol_filename_trans_t * rule, const qpol_type_t ** target) +{ + policydb_t *db = NULL; + filename_trans_t *ft = NULL; + + if (target) { + *target = NULL; + } + + if (!policy || !rule || !target) { + ERR(policy, "%s", strerror(EINVAL)); + errno = EINVAL; + return STATUS_ERR; + } + + db = &policy->p->p; + ft = (filename_trans_t *) rule; + + *target = (qpol_type_t *) db->type_val_to_struct[ft->ttype - 1]; + + return STATUS_SUCCESS; +} + +int qpol_filename_trans_get_object_class(const qpol_policy_t * policy, const qpol_filename_trans_t * rule, + const qpol_class_t ** obj_class) +{ + policydb_t *db = NULL; + filename_trans_t *ft = 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; + ft = (filename_trans_t *) rule; + + *obj_class = (qpol_class_t *) db->class_val_to_struct[ft->tclass - 1]; + + return STATUS_SUCCESS; +} + +int qpol_filename_trans_get_trans_type(const qpol_policy_t * policy, const qpol_filename_trans_t * rule, const qpol_type_t ** output_type) +{ + policydb_t *db = NULL; + filename_trans_t *ft = NULL; + + if (output_type) { + *output_type = NULL; + } + + if (!policy || !rule || !output_type) { + ERR(policy, "%s", strerror(EINVAL)); + errno = EINVAL; + return STATUS_ERR; + } + + db = &policy->p->p; + ft = (filename_trans_t *) rule; + + *output_type = (qpol_type_t *) db->type_val_to_struct[ft->otype - 1]; + + return STATUS_SUCCESS; +} + +int qpol_filename_trans_get_default_type(const qpol_policy_t * policy, const qpol_filename_trans_t * rule, const qpol_type_t ** dflt) +{ + policydb_t *db = NULL; + filename_trans_t *ft = NULL; + + if (dflt) { + *dflt = NULL; + } + + if (!policy || !rule || !dflt) { + ERR(policy, "%s", strerror(EINVAL)); + errno = EINVAL; + return STATUS_ERR; + } + + db = &policy->p->p; + ft = (filename_trans_t *) rule; + + *dflt = (qpol_type_t *) db->type_val_to_struct[ft->otype - 1]; + + return STATUS_SUCCESS; +} + +int qpol_filename_trans_get_filename(const qpol_policy_t * policy, const qpol_filename_trans_t * rule, const char ** name) +{ + policydb_t *db = NULL; + filename_trans_t *ft = NULL; + + if (name) { + *name = NULL; + } + + if (!policy || !rule || !name) { + ERR(policy, "%s", strerror(EINVAL)); + errno = EINVAL; + return STATUS_ERR; + } + + db = &policy->p->p; + ft = (filename_trans_t *) rule; + + *name = ft->name; + + return STATUS_SUCCESS; +} + diff --git a/libqpol/src/libqpol.map b/libqpol/src/libqpol.map index dd293bc..6973cca 100644 --- a/libqpol/src/libqpol.map +++ b/libqpol/src/libqpol.map @@ -34,6 +34,7 @@ VERS_1.2 { qpol_policy_reevaluate_conds; qpol_portcon_*; qpol_range_trans_*; + qpol_filename_trans_*; qpol_role_*; qpol_syn_avrule_*; qpol_syn_terule_*; diff --git a/libqpol/src/module_compiler.c b/libqpol/src/module_compiler.c index dc19798..b06e285 100644 --- a/libqpol/src/module_compiler.c +++ b/libqpol/src/module_compiler.c @@ -1247,6 +1247,18 @@ void append_role_allow(role_allow_rule_t * role_allow_rules) } /* this doesn't actually append, but really prepends it */ +void append_filename_trans(filename_trans_rule_t * filename_trans_rules) +{ + avrule_decl_t *decl = stack_top->decl; + + /* filename transitions are not allowed within conditionals */ + assert(stack_top->type == 1); + + filename_trans_rules->next = decl->filename_trans_rules; + decl->filename_trans_rules = filename_trans_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; diff --git a/libqpol/src/policy_define.c b/libqpol/src/policy_define.c index c94f7aa..0f3a45a 100644 --- a/libqpol/src/policy_define.c +++ b/libqpol/src/policy_define.c @@ -2133,7 +2133,7 @@ int define_role_trans(void) /* 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)) + if (role_set_expand(&roles, &e_roles, policydbp, NULL, NULL)) #else if (role_set_expand(&roles, &e_roles, policydbp)) #endif @@ -2226,6 +2226,190 @@ int define_role_allow(void) return 0; } +avrule_t *define_cond_filename_trans(void) +{ + yyerror("type transitions with a filename not allowed inside " + "conditionals\n"); + return COND_ERR; +} + +int define_filename_trans(void) +{ + char *id, *name = NULL; + type_set_t stypes, ttypes; + ebitmap_t e_stypes, e_ttypes; + ebitmap_t e_tclasses; + ebitmap_node_t *snode, *tnode, *cnode; + filename_trans_t *ft; + filename_trans_rule_t *ftr; + class_datum_t *cladatum; + type_datum_t *typdatum; + uint32_t otype; + unsigned int c, s, t; + int add; + + if (pass == 1) { + /* stype */ + while ((id = queue_remove(id_queue))) + free(id); + /* ttype */ + while ((id = queue_remove(id_queue))) + free(id); + /* tclass */ + while ((id = queue_remove(id_queue))) + free(id); + /* otype */ + id = queue_remove(id_queue); + free(id); + /* name */ + id = queue_remove(id_queue); + free(id); + return 0; + } + + + add = 1; + type_set_init(&stypes); + while ((id = queue_remove(id_queue))) { + if (set_types(&stypes, id, &add, 0)) + goto bad; + } + + add =1; + type_set_init(&ttypes); + while ((id = queue_remove(id_queue))) { + if (set_types(&ttypes, id, &add, 0)) + goto bad; + } + + ebitmap_init(&e_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(&e_tclasses, cladatum->s.value - 1, TRUE)) { + yyerror("Out of memory"); + goto bad; + } + free(id); + } + + id = (char *)queue_remove(id_queue); + if (!id) { + yyerror("no otype in transition definition?"); + goto bad; + } + if (!is_id_in_scope(SYM_TYPES, id)) { + yyerror2("type %s is not within scope", id); + free(id); + goto bad; + } + typdatum = hashtab_search(policydbp->p_types.table, id); + if (!typdatum) { + yyerror2("unknown type %s used in transition definition", id); + goto bad; + } + free(id); + otype = typdatum->s.value; + + name = queue_remove(id_queue); + if (!name) { + yyerror("no pathname specified in filename_trans definition?"); + goto bad; + } + + /* We expand the class set into seperate rules. We expand the types + * just to make sure there are not duplicates. They will get turned + * into seperate rules later */ + ebitmap_init(&e_stypes); + if (type_set_expand(&stypes, &e_stypes, policydbp, 1)) + goto bad; + + ebitmap_init(&e_ttypes); + if (type_set_expand(&ttypes, &e_ttypes, policydbp, 1)) + goto bad; + + ebitmap_for_each_bit(&e_tclasses, cnode, c) { + if (!ebitmap_node_get_bit(cnode, c)) + continue; + ebitmap_for_each_bit(&e_stypes, snode, s) { + if (!ebitmap_node_get_bit(snode, s)) + continue; + ebitmap_for_each_bit(&e_ttypes, tnode, t) { + if (!ebitmap_node_get_bit(tnode, t)) + continue; + + for (ft = policydbp->filename_trans; ft; ft = ft->next) { + if (ft->stype == (s + 1) && + ft->ttype == (t + 1) && + ft->tclass == (c + 1) && + !strcmp(ft->name, name)) { + yyerror2("duplicate filename transition for: filename_trans %s %s %s:%s", + name, + policydbp->p_type_val_to_name[s], + policydbp->p_type_val_to_name[t], + policydbp->p_class_val_to_name[c]); + goto bad; + } + } + + ft = malloc(sizeof(*ft)); + if (!ft) { + yyerror("out of memory"); + goto bad; + } + memset(ft, 0, sizeof(*ft)); + + ft->next = policydbp->filename_trans; + policydbp->filename_trans = ft; + + ft->name = strdup(name); + if (!ft->name) { + yyerror("out of memory"); + goto bad; + } + ft->stype = s + 1; + ft->ttype = t + 1; + ft->tclass = c + 1; + ft->otype = otype; + } + } + + /* Now add the real rule since we didn't find any duplicates */ + ftr = malloc(sizeof(*ftr)); + if (!ftr) { + yyerror("out of memory"); + goto bad; + } + filename_trans_rule_init(ftr); + append_filename_trans(ftr); + + ftr->name = strdup(name); + ftr->stypes = stypes; + ftr->ttypes = ttypes; + ftr->tclass = c + 1; + ftr->otype = otype; + } + + free(name); + ebitmap_destroy(&e_stypes); + ebitmap_destroy(&e_ttypes); + ebitmap_destroy(&e_tclasses); + + return 0; + +bad: + free(name); + return -1; +} + static constraint_expr_t *constraint_expr_clone(constraint_expr_t * expr) { constraint_expr_t *h = NULL, *l = NULL, *e, *newe; diff --git a/libqpol/src/policy_parse.y b/libqpol/src/policy_parse.y index 84f4114..dc16c6f 100644 --- a/libqpol/src/policy_parse.y +++ b/libqpol/src/policy_parse.y @@ -98,6 +98,7 @@ extern char *qpol_src_inputlim;/* end of data */ %type require_decl_def %token PATH +%token FILENAME %token CLONE %token COMMON %token CLASS @@ -360,7 +361,10 @@ cond_rule_def : cond_transition_def | require_block { $$ = NULL; } ; -cond_transition_def : TYPE_TRANSITION names names ':' names identifier ';' +cond_transition_def : TYPE_TRANSITION names names ':' names identifier filename ';' + { $$ = define_cond_filename_trans() ; + if ($$ == COND_ERR) return -1;} + | TYPE_TRANSITION names names ':' names identifier ';' { $$ = define_cond_compute_type(AVRULE_TRANSITION) ; if ($$ == COND_ERR) return -1;} | TYPE_MEMBER names names ':' names identifier ';' @@ -395,7 +399,9 @@ 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 ';' +transition_def : TYPE_TRANSITION names names ':' names identifier filename ';' + {if (define_filename_trans()) return -1; } + | 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;} @@ -752,6 +758,9 @@ identifier : IDENTIFIER path : PATH { if (insert_id(yytext,0)) return -1; } ; +filename : FILENAME + { yytext[strlen(yytext) - 1] = '\0'; if (insert_id(yytext + 1,0)) return -1; } + ; number : NUMBER { $$ = strtoul(yytext,NULL,0); } ; diff --git a/libqpol/src/policy_scan.l b/libqpol/src/policy_scan.l index 75485f3..30203cd 100644 --- a/libqpol/src/policy_scan.l +++ b/libqpol/src/policy_scan.l @@ -235,6 +235,7 @@ POLICYCAP { return(POLICYCAP); } permissive | PERMISSIVE { return(PERMISSIVE); } "/"({alnum}|[_\.\-/])* { return(PATH); } +\"({alnum}|[_\.\-])+\" { return(FILENAME); } {letter}({alnum}|[_\-])*([\.]?({alnum}|[_\-]))* { return(IDENTIFIER); } {digit}+|0x{hexval}+ { return(NUMBER); } {digit}{1,3}(\.{digit}{1,3}){3} { return(IPV4_ADDR); } diff --git a/secmds/sesearch.c b/secmds/sesearch.c index ec0315f..e44b3bc 100644 --- a/secmds/sesearch.c +++ b/secmds/sesearch.c @@ -575,6 +575,95 @@ static void print_te_results(const apol_policy_t * policy, const options_t * opt free(expr); } +static int perform_ft_query(const apol_policy_t * policy, const options_t * opt, apol_vector_t ** v) +{ + apol_filename_trans_query_t *ftq = NULL; + int error = 0; + + if (!policy || !opt || !v) { + ERR(policy, "%s", strerror(EINVAL)); + errno = EINVAL; + return -1; + } + + if (!opt->type == QPOL_RULE_TYPE_TRANS && !opt->all) { + *v = NULL; + return 0; /* no search to do */ + } + + ftq = apol_filename_trans_query_create(); + if (!ftq) { + ERR(policy, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + apol_filename_trans_query_set_regex(policy, ftq, opt->useregex); + if (opt->src_name) { + if (apol_filename_trans_query_set_source(policy, ftq, opt->src_name)) { + error = errno; + goto err; + } + } + if (opt->tgt_name) { + if (apol_filename_trans_query_set_target(policy, ftq, opt->tgt_name, opt->indirect)) { + error = errno; + goto err; + } + } + + if (apol_filename_trans_get_by_query(policy, ftq, v)) { + error = errno; + goto err; + } + + apol_filename_trans_query_destroy(&ftq); + return 0; + + err: + apol_vector_destroy(v); + apol_filename_trans_query_destroy(&ftq); + ERR(policy, "%s", strerror(error)); + errno = error; + return -1; +} + +static void print_ft_results(const apol_policy_t * policy, const options_t * opt, const apol_vector_t * v) +{ + qpol_policy_t *q = apol_policy_get_qpol(policy); + size_t i, num_rules = 0; + const qpol_filename_trans_t *rule = NULL; + char *tmp = NULL, *rule_str = NULL, *expr = NULL; + char enable_char = ' ', branch_char = ' '; + qpol_iterator_t *iter = NULL; + const qpol_cond_t *cond = NULL; + uint32_t enabled = 0, list = 0; + + if (!(num_rules = apol_vector_get_size(v))) + goto cleanup; + + fprintf(stdout, "Found %zd named file transition rules:\n", num_rules); + + for (i = 0; i < num_rules; i++) { + enable_char = branch_char = ' '; + if (!(rule = apol_vector_get_element(v, i))) + goto cleanup; + + if (!(rule_str = apol_filename_trans_render(policy, rule))) + goto cleanup; + fprintf(stdout, "%s %s\n", rule_str, expr ? expr : ""); + free(rule_str); + rule_str = NULL; + free(expr); + expr = NULL; + } + + cleanup: + free(tmp); + free(rule_str); + free(expr); +} + static int perform_ra_query(const apol_policy_t * policy, const options_t * opt, apol_vector_t ** v) { apol_role_allow_query_t *raq = NULL; @@ -1128,6 +1217,18 @@ int main(int argc, char **argv) print_te_results(policy, &cmd_opts, v); fprintf(stdout, "\n"); } + + if (cmd_opts.all || cmd_opts.type == QPOL_RULE_TYPE_TRANS) { + apol_vector_destroy(&v); + if (perform_ft_query(policy, &cmd_opts, &v)) { + rt = 1; + goto cleanup; + } + + print_ft_results(policy, &cmd_opts, v); + fprintf(stdout, "\n"); + } + apol_vector_destroy(&v); if (perform_ra_query(policy, &cmd_opts, &v)) { rt = 1; -- 1.7.6.2 diff -up setools-3.3.7/libapol/include/apol/Makefile.am.filenametrans setools-3.3.7/libapol/include/apol/Makefile.am --- setools-3.3.7/libapol/include/apol/Makefile.am.filenametrans 2009-07-14 14:03:27.000000000 -0400 +++ setools-3.3.7/libapol/include/apol/Makefile.am 2011-10-26 16:24:59.948130442 -0400 @@ -27,6 +27,7 @@ apol_HEADERS = \ relabel-analysis.h \ render.h \ role-query.h \ + ftrule-query.h \ terule-query.h \ type-query.h \ types-relation-analysis.h \ diff -up setools-3.3.7/libapol/include/apol/Makefile.in.filenametrans setools-3.3.7/libapol/include/apol/Makefile.in --- setools-3.3.7/libapol/include/apol/Makefile.in.filenametrans 2010-05-12 10:01:06.000000000 -0400 +++ setools-3.3.7/libapol/include/apol/Makefile.in 2011-10-26 16:25:07.834107745 -0400 @@ -378,6 +378,7 @@ apol_HEADERS = \ relabel-analysis.h \ render.h \ role-query.h \ + ftrule-query.h \ terule-query.h \ type-query.h \ types-relation-analysis.h \ diff -up setools-3.3.7/libqpol/include/qpol/Makefile.am.filenametrans setools-3.3.7/libqpol/include/qpol/Makefile.am --- setools-3.3.7/libqpol/include/qpol/Makefile.am.filenametrans 2011-10-26 16:22:28.723523155 -0400 +++ setools-3.3.7/libqpol/include/qpol/Makefile.am 2011-10-26 16:22:41.283493767 -0400 @@ -25,6 +25,7 @@ qpol_HEADERS = \ role_query.h \ syn_rule_query.h \ terule_query.h \ + ftrule_query.h \ type_query.h \ user_query.h \ util.h diff -up setools-3.3.7/libqpol/include/qpol/Makefile.in.filenametrans setools-3.3.7/libqpol/include/qpol/Makefile.in --- setools-3.3.7/libqpol/include/qpol/Makefile.in.filenametrans 2010-05-12 10:01:07.000000000 -0400 +++ setools-3.3.7/libqpol/include/qpol/Makefile.in 2011-10-26 16:22:56.375457650 -0400 @@ -376,6 +376,7 @@ qpol_HEADERS = \ role_query.h \ syn_rule_query.h \ terule_query.h \ + ftrule_query.h \ type_query.h \ user_query.h \ util.h