From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from jazzdrum.ncsc.mil (zombie.ncsc.mil [144.51.88.131]) by tarius.tycho.ncsc.mil (8.13.1/8.13.1) with SMTP id l48EjSYQ021377 for ; Tue, 8 May 2007 10:45:28 -0400 Received: from exchange.columbia.tresys.com (jazzdrum.ncsc.mil [144.51.5.7]) by jazzdrum.ncsc.mil (8.12.10/8.12.10) with SMTP id l48EjQhM021370 for ; Tue, 8 May 2007 14:45:26 GMT Message-ID: <46408CF6.1050409@manicmethod.com> Date: Tue, 08 May 2007 10:45:10 -0400 From: Joshua Brindle MIME-Version: 1.0 To: Karl MacMillan CC: selinux@tycho.nsa.gov Subject: Re: [PATCH] Basic policy representation References: In-Reply-To: Content-Type: text/plain; charset=ISO-8859-1; format=flowed Sender: owner-selinux@tycho.nsa.gov List-Id: selinux@tycho.nsa.gov Karl MacMillan wrote: > Add support for the basic policy object model and the sepol_policy > and sepol_module objects to libsepol. This version has significant > changes from the last posted version: > > 1) sepol_handle is passed everywhere > 2) public and private interfaces to the object system are correctly > split (into policy.[c,h] and policy_internal.[c,h]. > 3) object ouput has been converted from writing to a FILE to returning > allocated strings. This will help integrate better with scripting > languages. > 4) Basic documentation is included for the base objects. > 5) Enums are used instead of defines - this is a change from the style > for libsepol, but it makes documenting the enums much easier. > > Signed-off-by: User "Karl MacMillan " > --- > > 7 files changed, 1667 insertions(+), 4 deletions(-) > libsepol/include/sepol/policy.h | 522 +++++++++++++++++++++++++++++++ > libsepol/src/policy.c | 638 +++++++++++++++++++++++++++++++++++++++ > libsepol/src/policy_internal.c | 102 ++++++ > libsepol/src/policy_internal.h | 269 ++++++++++++++++ > libsepol/tests/libsepol-tests.c | 10 > libsepol/tests/test-policy.c | 118 +++++++ > libsepol/tests/test-policy.h | 12 > > > diff -r cacdf4377ebf -r bd4ee6e00a63 libsepol/include/sepol/policy.h > --- a/libsepol/include/sepol/policy.h Mon May 07 15:50:27 2007 -0400 > +++ b/libsepol/include/sepol/policy.h Mon May 07 18:03:03 2007 -0400 > @@ -0,0 +1,522 @@ > +/* Author : Karl MacMillan */ > + > +#ifndef __sepol_policy_h__ > +#define __sepol_policy_h__ > + > +#include > + > +#include > +#include > +#include > + > +#include > +#include > +#include > + > +/** > + * \defgroup sepol_policy sepol_policy: policy representation > + * Introduction to the policy object system > + * > + * > + * The policy is represented as a tree of objects that loosely > + * resemble an abstract syntax tree or intermediate representation > + * commonly found in compilers. This tree representation is used as > + * the output of the policy parser the format for selinux policy > + * modules. The data structures are also intended to be flexible > + * enough to represent an selinux policy for syntax/semantic checking, > + * analysis, generation, and storage. > + * > + * The basic structure is that of a tree holding selinux policy > + * language components (e.g., type declarations, rules, conditional > + * blocks, etc.). To implement this tree structure in a form that can > + * be processed easily, a basic object orientied structure is > + * implemented in C. > + * > + * The object oriented system allows the use of polymorphic functions, > + * making it possible to process objects in the tree with only limited > + * informatio about the specific types (e.g., it is possible to > + * traverse the tree and output all of the objects as strings without > + * the traversal function knowing detailed type information about each > + * object - it simple class sepol_object_strout on each object). > + * > + * See sepol_object and sepol_parent for more information on this object > + * oriented type system. > + * > + */ > + > +/** > + * \ingroup sepol_policy > + * > + * Every type in the policy object system is identified > + * by a numberic typeid. > + */ > +enum sepol_typeid { > + SEPOL_TYPEID_NONE, /** special typeid representing no type */ > + SEPOL_TYPEID_OBJECT, /** typeid for base class of all objects */ > + SEPOL_TYPEID_PARENT, /** typeid for base class of objects that contain other objects */ > + SEPOL_TYPEID_POLICY, /** typeid for policy object */ > + SEPOL_TYPEID_MODULE, /** typeid for the module object */ > + SEPOL_TYPEID_BLOCK, /** tyepid for the block object */ > + SEPOL_TYPEID_COND, /** typeid for the cond object */ > + SEPOL_TYPEID_OPTIONAL, /** typeid for the optional object */ > + SEPOL_TYPEID_TYPE, /** typed for the type object */ > + SEPOL_TYPEID_CLASS, /** typeid for the class object */ > + SEPOL_TYPEID_ATTRIBUTE, /** typeid for the attribute object */ > + SEPOL_TYPEID_TYPEALIAS, /** typeid for the typealias object */ > + SEPOL_TYPEID_BOOL, /** typeid for the bool object */ > + SEPOL_TYPEID_AVRULE, /** typeid for the avrule object */ > + SEPOL_TYPEID_TYPERULE, /** typeid for the typerule object */ > + SEPOL_TYPEID_SECURITY_CONTEXT, /** typeid for the securit context object */ > + SEPOL_TYPEID_ISID, /** typeid for the isid object */ > + SEPOL_TYPEID_TYPEATTRIBUTE, /** typeid for the typeattribute object */ > + SEPOL_TYPEID_COND_EXPR, /** typeid for the cond expr object */ > + SEPOL_TYPEID_SENS, /** typeid for the sends object */ > + SEPOL_TYPEID_DOMINANCE, /** typeid for the dominance object */ > + SEPOL_TYPEID_CATEGORY, /** typeid for the category object */ > + SEPOL_TYPEID_ROLE_DOMINANCE, /** typeid for the role dominance object */ > + SEPOL_TYPEID_ROLE /** typeid for the role object */ > +}; > Do you think typeid is really a good word to use here? This is possibly very confusing (others have already mentioned to me that it was confusing) > + > +/** > + * \ingroup sepol_policy > + * > + * Convert a typeid to a string representation. The returned string > + * is constant and should not be altered or freed. > + * > + * @param typeid typeid to convert to string > + * > + * \retval string string representing the typeid > + */ > +const char *sepol_typeid_tostring(int typeid); > + > +/** > + * \ingroup sepol_policy > + * \struct sepol_object > + * > + * sepol_object is the base class of all objects in this type system. > + * There is no way to directly create an sepol_object - it is an > + * abstract base class. > + * > + * The type system works by: > + * - mandating that sepol_object (or one of its subclasses) be the > + * first entry in every struct. This allows the structs to be > + * freely cast to an sepol_object or any of the other objects > + * in the hierarchy of that struct. > + * - Storing information about the types in the form of IDs. This > + * allows callers to determine type information at runtime. > + * - Storing function pointers to class specific function > + * implementations in each object instance. This allows functions > + * to have a limited form of polymorphism. > + * > + * sepol_object is also the parent class of all objects that are > + * exclusively leaves in the tree (i.e., objects that cannot contain > + * other objects). > + * > + * Properties that all sepol_objects share: > + * - string pool (strpool): [optional] an objpool for storing > + * strings stored in the objects. The object may be the owner of > + * the string pool (see sepol_object_is_strpool_owner), reference > + * the string pool of another object (usually the root of a policy > + * tree), or not have a string pool at all. > + * - type identifier (typeid): The sepol_typeid for this object. > + */ > +struct sepol_object; > + > +/** > + * \ingroup sepol_policy > + * > + * Convert an object to an sepol_object > + * > + * @param x object > + */ > +#define SEPOL_OBJECT(x) ((struct sepol_object *)x) > + > +/** > + * \ingroup sepol_policy > + * > + * Free an sepol_object. This can be called for any > + * subclass of sepol_object. > + * > + * @param n object to free > + * > + * \retval SEPOL_OK success > + * \retval <0 error > + */ > +extern int sepol_object_free(struct sepol_handle *h, struct sepol_object *o); > + > +/** > + * \ingroup sepol_policy > + * > + * Make this object the owner of a string pool. See sepol_object for > + * more information on string pools. > + * > + * @param o object to which to add string pool > + * > + * \retval SEPOL_OK success > + * \retval SEPOL_ENOMEM out of memory > + */ > +extern int sepol_object_create_strpool(struct sepol_handle *h, struct sepol_object *o); > + > +/** > + * \ingroup sepol_policy > + * > + * Return the strpool for this object if any. > + * > + * @param o object from which to return string pool. > + * > + * \retval non-NULL string pool this object is using. > + * \retval NULL object does not use string pool. > + */ > +extern struct sepol_objpool *sepol_object_get_strpool(struct sepol_object *o); > + > +/** > + * \ingroup sepol_policy > + * > + * Determine whether the object is the owner of its string pool (if > + * it has one). > + * > + * @param o object to check > + * > + * \retval 0 object does not own or does not have a string pool > + * \retval 1 object owns its string pool > + */ > +extern char sepol_object_is_strpool_owner(struct sepol_object *o); > + > + > +/** > + * \ingroup sepol_policy > + * > + * Return the typeid for the object. > + * > + * @param o object from which to return the type id. > + * > + * \retval >0 typeid for the object > + */ > +extern uint32_t sepol_object_get_typeid(struct sepol_object *o); > + > +/** > + * \ingroup sepol_policy > + * > + * Determine whether the object is an instance of the object type > + * represented by a typeid. This function checks both the specific > + * object type (as returned by sepol_object_get_typeid) and the > + * parent type for the object. > + * > + * @param o object to check > + * @param typeid typeid > + * > + * \retval 0 object is not an instance of the type > + * \retval 1 object is an instance of the type > + */ > +extern char sepol_object_isinstance(struct sepol_object *o, uint32_t typeid); > + > +/** > + * \ingroup sepol_policy > + * > + * Return the parent of this object (if any). > + * > + * @param o object for which to return parent > + * > + * \retval non-NULL pointer to parent object > + * \retval NULL object has no parent > + */ > +extern struct sepol_parent *sepol_object_get_parent(struct sepol_object *o); > + > +/** > + * \ingroup sepol_policy > + * > + * Specify the output for various sepol_*_tostring functions. > + */ > +enum sepol_tostring_style { > + SEPOL_TOSTRING_RAW, /** raw policy language */ > + SEPOL_TOSTRING_REFPOL, /** refpol style output */ > + SEPOL_TOSTRING_DEBUG /** debugging output */ > +}; > + > +/** > + * \ingroup sepol_policy > + * > + * Convert an sepol_object into a string representation. If the > + * returned string is of 0 length (return is 0), str will be an > + * allocated, 0 length string that should be freed by the caller. > + * > + * @param h sepol_handle (may be NULL) > + * @param o object to convert to a string > + * @param style style of the output - see sepol_tostring_style > + * @param str output string - this string is allocated by the function > + * and should be freed by the caller using free() > + * > + * \retval >=0 Success - the size of the string is returned > + * \retval <0 Failure - str will be undefined and does not need to be freed. > + */ > +extern int sepol_object_tostring(struct sepol_handle *h, struct sepol_object *o, > + int style, char **str); > + > +/** > + * \ingroup sepol_policy > + * > + * Convert an sepol_object into a string representation for the > + * closure of that object. Some objects - typically that contain > + * other objects - need a string to represent the beginning _and_ > + * the end of that object. For example: > + * > + * \code > + * if (foo) { > + * allow foo bar : file read; > + * } > + * \endcode > + * > + * In this example "if (foo) }" would be printed by > + * sepol_object_tostring and "}} printed by > + * sepol_object_tostring_close on the same conditional object. If the > + * returned string is of 0 length (return is 0), str will be an > + * allocated, 0 length string that should be freed by the caller. > + * > + * @param h sepol_handle (may be NULL) > + * @param o object to convert to a string > + * @param style style of the output - see sepol_tostring_style > + * @param str output string - this string is allocated by the function > + * and should be freed by the caller using free() > + * > + * \retval >=0 Success - the size of the string is returned > + * \retval <0 Failure - str will be undefined and does not need to be freed. > + */ > +extern int sepol_object_tostring_close(struct sepol_handle *h, struct sepol_object *o, > + int style, char **str); > + > +/** > + * \ingroup sepol_policy > + * \struct sepol_parent > + * > + * sepol_parent is the parent class of all objects that can contain > + * other objects in the tree. Having a single base class for all parent > + * objects allows writing functions that can traverse the tree without > + * knowing the details about most of the objects in the tree. > + */ > +struct sepol_parent; > + > +/** > + * \ingroup sepol_policy > + * > + * Convert an object to an sepol_parent > + * > + * @param x object > + */ > +#define SEPOL_PARENT(x) ((struct sepol_parent *)x) > + > +/** > + * \ingroup sepol_policy > + * > + * Free a parent object and all of its children (if any). This > + * function traverses a policy tree starting at the parent node passed > + * in destroy each object it encounters (by (calling > + * sepol_object_free). > + * > + * @param h sepol_handle (may be NULL) > + * @param p sepol_parent object > + * > + * \retval SEPOL_OK success > + * \retval SEPOL_ENOMEM out of memory > + */ > +extern int sepol_parent_free_tree(struct sepol_handle *h, struct sepol_parent *p); > + > +/** > + * \ingroup sepol_policy > + * > + * Append an object as a child of this parent. An object can only > + * be the child of a single parent - to move an object from one > + * part of the tree to another (and change the parent), remove the > + * child from the current parent first before appending to the new > + * parent. > + * > + * @param h sepol_handle (may be NULL) > + * @param p sepol_parent to which to append child object > + * @param o object to append (parent will be set) > + * > + * \retval SEPOL_OK success > + * \retval SEPOL_EEXIST object is already a child of another parent > + * \retval SEPOL_ENOMEM out of memory > + */ > +extern int sepol_parent_append(struct sepol_handle *h, struct sepol_parent *p, > + struct sepol_object *o); > + > +/** > + * \ingroup sepol_policy > + * > + * Extend the children of an sepol_parent with the objects returned by > + * an iterator. Each object will be appended using > + * sepol_parent_append. If there is an error from adding any of the > + * children some of the objects may have been added. The iterator will > + * be left in the position of the object that caused an error. > + * > + * @param h sepol_handle (may be NULL) > + * @param p sepol_parent to which to add children > + * @param iter iterator from which to add children > + * > + * \retval SEPOL_OK success > + * \retval SEPOL_EEXIST object is already a child of another parent > + * \retval SEPOL_ENOMEM out of memory > + */ > +extern int sepol_parent_extend(struct sepol_handle *h, struct sepol_parent *p, > + struct sepol_iter *iter); > + > +/** > + * \ingroup sepol_policy > + * > + * Convenience function similar to sepol_parent_extend that takes a > + * list instead of an interator. > + * > + * @param h sepol_handle (may be NULL) > + * @param p sepol_parent to which to add objects > + * @param list sepol_list from which to add objects > + * > + * \retval SEPOL_OK success > + * \retval SEPOL_EEXIST object is already a child of another parent > + * \retval SEPOL_ENOMEM out of memory > + */ > +extern int sepol_parent_extend_list(struct sepol_handle *h, struct sepol_parent *p, > + struct sepol_list *list); > + > +/** > + * \ingroup sepol_policy > + * > + * Delete a child object from the sepol_parent. Like sepol_list_del, > + * the iterator will not be valid after a call to this function. > + * > + * @param h sepol_handle (may be NULL) > + * @param p sepol_parent from which to delete child > + * @param iter iterator pointing to a child object of p > + * > + * \retval SEPOL_OK success > + */ > +extern int sepol_parent_del(struct sepol_handle *h, struct sepol_parent *p, > + struct sepol_iter *iter); > + > +/** > + * \ingroup sepol_policy > + * > + * Insert a child object into the list of children for the > + * sepol_parent. See sepol_list_insert for more information on the > + * semantics of this insert. > + * > + * @param h sepol_handle (may be NULL) > + * @param p sepol_parent to which to insert child object > + * @param iter iterator representing the position to insert the child object > + * @param o child object to insert > + * > + * \retval SEPOL_OK success > + * \retval SEPOL_EEXIST object is already a child of another parent > + * \retval SEPOL_ENOMEM out of memory > + */ > +extern int sepol_parent_insert(struct sepol_handle *h, struct sepol_parent *p, > + struct sepol_iter *iter, struct sepol_object *o); > + > +/** > + * \ingroup sepol_policy > + * > + * Set an iterator to iterate over the children of an sepol_parent. > + * > + * @param h sepol_handle (may be NULL) > + * @param p sepol_parent > + * @param iter iterator to set to iterate over children > + * > + * \retval SEPOL_OK success > + * \retval SEPOL_ENOMEM out of memory > + */ > +extern int sepol_parent_children(struct sepol_handle *h, struct sepol_parent *p, > + struct sepol_iter *iter); > + > +/** > + * \ingroup sepol_policy > + * > + * Return the list containing the children of the sepol_parent > + * object. This is the actual list used to store children of the > + * object, so changes will be reflected in the sepol_parent. It is > + * important that deletions and insertions use sepol_parent_del and > + * sepol_parent_insert or that the parent property of the objects > + * is properly set. > + * > + * @param p sepol_parent > + * > + * \retval non-NULL pointer to the list of children > + */ > +struct sepol_list *sepol_parent_get_children(struct sepol_parent *parent); > + > + > +/** > + * \ingroup sepol_policy > + * > + * Traversal of a policy tree rooted at a sepol_parent can take many > + * forms. This enumeration is used to set the traversal strategy. See > + * http://en.wikipedia.org/wiki/Tree_traversal for more information. > + * > + * The hybrid strategy combines both preorder and postorder > + * traversal. This means that each parent node will be visited twice: > + * once before its children are traversed and once afterward. The > + * second traversal can be detected by checking the flag indicating > + * that the parent has been visited (see sepol_parent_isvisited). > + */ > +enum sepol_parent_traverse_strategy { > + SEPOL_TRAVERSE_POSTORDER, /** traverse the tree in postorder */ > + SEPOL_TRAVERSE_PREORDER, /** traverse the tree in preorder */ > + SEPOL_TRAVERSE_HYBRID /** traverse the tree combining preorder and postorder */ > +}; > + > +/** > + * \ingroup sepol_policy > + * > + * Traverse a policy tree using parent as the root node of the tree. The traversal > + * strategy is controlled by sepol_parent_traverse_strategy. > + * > + * @param h sepol_handle (may be null) > + * @param parent sepol_parent > + * @param iter iterator to represent traversal state > + * @param strategy traversal strategy - see sepol_parent_traverse_strategy > + * > + * \retval SEPOL_OK success > + * \retval SEPOL_ENOMEM out of memory > + */ > +extern int sepol_parent_traverse(struct sepol_handle *h, struct sepol_parent *parent, > + struct sepol_iter *iter, int strategy); > + > +/** > + * \ingroup sepol_policy > + * > + * Return whether an object has already been visited before during this tree > + * traversal. See sepol_parent_traverse_strategy for more information. > + * > + * @param iter iterator > + * > + * \retval 0 object has not been previously visited > + * \retval 1 object has been previously visited > + */ > +char sepol_parent_isvisited(struct sepol_iter *iter); > + > is it really necessary to use a char here? granted its smaller but it also doesn't really convey to someone new to the code what is going on. Perhaps a bool typemap? or short int? > +struct sepol_policy; > + > +extern int sepol_policy_free(struct sepol_handle *h, struct sepol_policy *o); > +extern int sepol_policy_create(struct sepol_handle *h, > + struct sepol_policy **policy); > + > +extern char sepol_policy_get_mls(struct sepol_policy *o); > +extern int sepol_policy_set_mls(struct sepol_policy *o, char mls); > + > +struct sepol_module; > + > +extern int sepol_module_free(struct sepol_handle *h, struct sepol_module *o); > +extern int sepol_module_create(struct sepol_handle *h, > + struct sepol_module **module); > +extern int sepol_module_create_tree(struct sepol_handle *h, > + struct sepol_module **module, > + struct sepol_parent *root); > + > +int sepol_module_set_name(struct sepol_module *module, char *name); > +const char *sepol_module_get_name(struct sepol_module *module); > + > +int sepol_module_set_version(struct sepol_module *module, char *version); > +const char *sepol_module_get_version(struct sepol_module *module); > + > +int sepol_module_set_isbase(struct sepol_module *module, char isbase); > +char sepol_module_get_isbase(struct sepol_module *module); > + > +#endif > diff -r cacdf4377ebf -r bd4ee6e00a63 libsepol/src/policy.c > --- a/libsepol/src/policy.c Mon May 07 15:50:27 2007 -0400 > +++ b/libsepol/src/policy.c Mon May 07 18:03:03 2007 -0400 > @@ -0,0 +1,638 @@ > +/* > + * Author : Karl MacMillan > + * > + * Copyright (C) 2007 Red Hat, Inc. > + * > + * 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_internal.h" > +#include "debug.h" > +#include "dso.h" > + > +#include > +#include > +#include > + > +/* > + * SEPOL_OBJECT > + */ > + > +static char *typeid_strings[] = { > + "none", > + "object", > + "parent", > + "policy", > + "module", > + "block", > + "cond", > + "optional", > + "type", > + "class", > + "attribute", > + "typealias", > + "boolean", > + "avrule", > + "typerule", > + "security context", > + "initial sid", > + "typeattribute", > + "conditional expression", > + "sensitivity", > + "dominance", > + "category", > + "role dominance", > + "role" > +}; > + > It would be nice if these were in the same place as the enum so they could be updated easier, but I understand that the strings are private and the enum is exported :\ > +const char *sepol_typeid_tostring(int typeid) > +{ > + assert(typeid < sizeof(typeid_strings)); > + return typeid_strings[typeid]; > +} > +hidden_def(sepol_typeid_tostring) > + > +int sepol_object_free(struct sepol_handle *h, struct sepol_object *o) > +{ > + assert(o->methods->free); > + > + return o->methods->free(h, o); > +} > +hidden_def(sepol_object_free) > + > +#define SEPOL_STRPOOL_SIZE 64 > +int sepol_object_create_strpool(struct sepol_handle *h, struct sepol_object *o) > +{ > + int ret; > + > + ret = sepol_objpool_create(h, &o->strpool, (sepol_objpool_hash_t)sepol_symhash, > + (sepol_objpool_cmp_t)sepol_symcmp, free, > + SEPOL_STRPOOL_SIZE); > + ret_check(ret); > + o->flags |= SEPOL_OBJECT_STRPOOL_OWNER; > + > + return ret; > +} > +hidden_def(sepol_object_create_strpool) > + > +struct sepol_objpool *sepol_object_get_strpool(struct sepol_object *o) > +{ > + return o->strpool; > +} > +hidden_def(sepol_object_get_strpool) > + > +char sepol_object_is_strpool_owner(struct sepol_object *o) > +{ > + return (o->flags & SEPOL_OBJECT_STRPOOL_OWNER) != 0; > +} > +hidden_def(sepol_object_is_strpool_owner) > + > +uint32_t sepol_object_get_typeid(struct sepol_object *o) > +{ > + return o->typeid; > +} > +hidden_def(sepol_object_get_typeid) > + > +char sepol_object_isinstance(struct sepol_object *o, uint32_t typeid) > +{ > + if (o->typeid == typeid || o->sclass_typeid == typeid) > + return 1; > + else return 0; > +} > +hidden_def(sepol_object_isinstance) > + > +struct sepol_parent *sepol_object_get_parent(struct sepol_object *o) > +{ > + return o->parent; > +} > +hidden_def(sepol_object_get_parent) > + > +int sepol_object_tostring(struct sepol_handle *h, struct sepol_object *o, > + int style, char **str) > +{ > + if (o->methods->tostring) { > + return o->methods->tostring(h, o, style, str); > + } else { > + if (style == SEPOL_TOSTRING_DEBUG) { > + return asprintf(str, "[sepol_object(%s) at %p]", > + sepol_typeid_tostring(o->typeid), o); > + } > + > + /* Even though we are returning an empty string, we still > + * need to allocated an empty string to return. This > + * matches the behavior of asprintf. > + */ > + *str = strdup(""); > + if (*str == NULL) > + return -1; > + return 0; > + } > +} > +hidden_def(sepol_object_tostring) > + > +int sepol_object_tostring_close(struct sepol_handle *h, struct sepol_object *o, > + int style, char **str) > +{ > + if (o->methods->tostring_close) { > + return o->methods->tostring_close(h, o, style, str); > + } else { > + if (style == SEPOL_TOSTRING_DEBUG) { > + return asprintf(str, "[close: sepol_object(%s) at %p]", > + sepol_typeid_tostring(o->typeid), o); > + } > + > + /* Even though we are returning an empty string, we still > + * need to allocated an empty string to return. This > + * matches the behavior of asprintf. > + */ > + *str = strdup(""); > + if (*str == NULL) > + return -1; > + return 0; > + } > +} > +hidden_def(sepol_object_tostring_close) > + > +/* > + * SEPOL_PARENT > + */ > + > +int sepol_parent_free_tree(struct sepol_handle *h, struct sepol_parent *p) > +{ > + int ret; > + struct sepol_iter *iter; > + struct sepol_object *cur; > + > + ret = sepol_iter_create(h, &iter); > + if (ret < 0) > + goto out; > + > + ret = sepol_parent_traverse(h, p, iter, SEPOL_TRAVERSE_POSTORDER); > + if (ret < 0) > + goto out; > + > + sepol_foreach(h, ret, cur, iter) { > + int ret2; > + char *str; > + ret2 = sepol_object_tostring(h, cur, SEPOL_TOSTRING_DEBUG, &str); > + assert(ret2 >= 0); > + printf("freeing %s", str); > + sepol_object_free(h, cur); > + free(str); > + } > + if (ret != SEPOL_ITERSTOP) > + goto out; > + > + ret = SEPOL_OK; > +out: > + sepol_iter_free(h, iter); > + return ret; > +} > +hidden_def(sepol_parent_free_tree) > + > +int sepol_parent_append(struct sepol_handle *h, struct sepol_parent *p, struct sepol_object *o) > +{ > + if (o->parent) > + return SEPOL_EEXIST; > + o->parent = p; > + return sepol_list_append(h, p->children, o); > +} > +hidden_def(sepol_parent_append) > + > +int sepol_parent_extend(struct sepol_handle *h, struct sepol_parent *p, struct sepol_iter *iter) > +{ > + int ret = SEPOL_OK; > + struct sepol_object *cur; > + > + sepol_foreach(h, ret, cur, iter) { > + ret = sepol_parent_append(h, p, cur); > + if (ret < 0) { > + return ret; > + } > + } > + if (ret != SEPOL_ITERSTOP) { > + return ret; > + } > + > + return SEPOL_OK; > +} > +hidden_def(sepol_parent_extend) > + > +int sepol_parent_extend_list(struct sepol_handle *h, struct sepol_parent *p, struct sepol_list *list) > +{ > + int ret; > + struct sepol_iter *iter; > + > + ret = sepol_iter_create(h, &iter); > + if (ret < 0) > + return ret; > + ret = sepol_list_begin(h, list, iter); > + if (ret < 0) { > + if (ret == SEPOL_ITERSTOP) > + return SEPOL_OK; > + else > + return ret; > + } > + ret = sepol_parent_extend(h, p, iter); > + sepol_iter_free(h, iter); > + > + return ret; > +} > +hidden_def(sepol_parent_extend_list) > + > +int sepol_parent_del(struct sepol_handle *h, struct sepol_parent *p, struct sepol_iter *iter) > +{ > + struct sepol_object *o; > + o = (struct sepol_object*)sepol_iter_get_data(h, iter); > + if (!o) { > + ERR(h, "error getting object from iterator"); > + return SEPOL_ERR; > + } > + o->parent = NULL; > + return sepol_list_del(h, p->children, iter); > +} > +hidden_def(sepol_parent_del) > + > +int sepol_parent_insert(struct sepol_handle *h, struct sepol_parent *p, > + struct sepol_iter *iter, struct sepol_object *o) > +{ > + if (o->parent) > + return SEPOL_EEXIST; > + o->parent = p; > + > + return sepol_list_insert(h, p->children, iter, o); > +} > +hidden_def(sepol_parent_insert) > + > + > +int sepol_parent_children(struct sepol_handle *h, struct sepol_parent *p, struct sepol_iter *iter) > +{ > + return sepol_list_begin(h, p->children, iter); > +} > +hidden_def(sepol_parent_children) > + > +struct sepol_list *sepol_parent_get_children(struct sepol_parent *parent) > +{ > + return parent->children; > +} > +hidden_def(sepol_parent_get_children) > + > + > +struct sepol_parent_traverse_state > +{ > + int strategy; > + char cur_flags; > + struct sepol_list *stack; > + void *object; > +}; > + > +static void *sepol_parent_iter_get_data(struct sepol_handle *h, struct sepol_iter *iter) > +{ > + struct sepol_parent_traverse_state *state; > + > + assert(iter); > + state = (struct sepol_parent_traverse_state*) > + sepol_iter_get_state(iter); > + assert(state); > + > + return state->object; > +} > + > +static int sepol_parent_iter_free(struct sepol_handle *h, void *data) > +{ > + struct sepol_parent_traverse_state *state = > + (struct sepol_parent_traverse_state*)data; > + > + if (state == NULL) > + return SEPOL_OK; > + > + if (state->stack) > + sepol_list_free(state->stack); > + free(state); > + > + return SEPOL_OK; > +} > + > +static int sepol_parent_traverse_preorder_next(struct sepol_handle *h, struct sepol_iter *iter) > +{ > + int ret; > + struct sepol_parent_traverse_state *state; > + struct sepol_object *object, *cur; > + struct sepol_iter *child_iter; > + > + state = sepol_iter_get_state(iter); > + > + ret = sepol_list_pop_back(h, state->stack, (void**)&object); > + > + if (ret == SEPOL_ERANGE) > + return SEPOL_ITERSTOP; > + else if (ret < 0) > + return ret; > + > + state->object = object; > + state->cur_flags = object->flags; > + > + if (sepol_object_isinstance(object, SEPOL_TYPEID_PARENT) && > + !(object->flags & SEPOL_OBJECT_VISITED)) { > + if (state->strategy == SEPOL_TRAVERSE_HYBRID) { > + object->flags |= SEPOL_OBJECT_VISITED; > + ret = sepol_list_append(h, state->stack, object); > + ret_check(ret); > + } > + ret = sepol_iter_create(h, &child_iter); > + ret_check(ret); > + ret = sepol_list_end(h, sepol_parent_get_children(SEPOL_PARENT(object)), > + child_iter); > + while (ret == SEPOL_OK) { > + cur = sepol_iter_get_data(h, child_iter); > + cur->flags &= ~SEPOL_OBJECT_VISITED; > + ret = sepol_list_append(h, state->stack, cur); > + if (ret < 0) > + break; > + ret = sepol_iter_prev(h, child_iter); > + } > + sepol_iter_free(h, child_iter); > + if (ret < 0 && ret != SEPOL_ITERSTOP) { > + return ret; > + } > + > + } > + return SEPOL_OK; > +} > + > +static int sepol_parent_traverse_postorder_next(struct sepol_handle *h, struct sepol_iter *iter) > +{ > + int ret; > + struct sepol_parent_traverse_state *state; > + struct sepol_object *object, *cur; > + struct sepol_iter *child_iter; > + > + state = sepol_iter_get_state(iter); > + > + while (1) { > + ret = sepol_list_pop_back(h, state->stack, (void**)&object); > + > + if (ret == SEPOL_ERANGE) > + return SEPOL_ITERSTOP; > + else if (ret < 0) > + return ret; > + > + if (object->flags & SEPOL_OBJECT_VISITED || > + !sepol_object_isinstance(object, SEPOL_TYPEID_PARENT)) { > + state->object = object; > + break; > + } else { > + object->flags |= SEPOL_OBJECT_VISITED; > + ret = sepol_list_append(h, state->stack, object); > + ret_check(ret); > + > + ret = sepol_iter_create(h, &child_iter); > + ret_check(ret); > + ret = sepol_list_end(h, sepol_parent_get_children(SEPOL_PARENT(object)), > + child_iter); > + while (ret == SEPOL_OK) { > + cur = sepol_iter_get_data(h, child_iter); > + cur->flags &= ~SEPOL_OBJECT_VISITED; > + ret = sepol_list_append(h, state->stack, cur); > + if (ret < 0) > + break; > + ret = sepol_iter_prev(h, child_iter); > + } > + sepol_iter_free(h, child_iter); > + if (ret < 0 && ret != SEPOL_ITERSTOP) { > + return ret; > + } > + } > + } > + return SEPOL_OK; > +} > + > +int sepol_parent_traverse(struct sepol_handle *h, struct sepol_parent *parent, > + struct sepol_iter *iter, int strategy) > +{ > + int ret; > + struct sepol_parent_traverse_state *state = NULL; > + > + state = calloc(1, sizeof(struct sepol_parent_traverse_state)); > > + if (state == NULL) > + return SEPOL_ENOMEM; > + > + ret = sepol_list_create(h, &state->stack); > + ret_goto(ret, err); > + > + state->strategy = strategy; > + sepol_iter_set_state(iter, state); > + > + if (state->strategy == SEPOL_TRAVERSE_POSTORDER) > + sepol_iter_set_next(iter, sepol_parent_traverse_postorder_next); > + else if (state->strategy == SEPOL_TRAVERSE_PREORDER || > + state->strategy == SEPOL_TRAVERSE_HYBRID) > + sepol_iter_set_next(iter, sepol_parent_traverse_preorder_next); > + else > + return SEPOL_ERR; > + sepol_iter_set_free(iter, sepol_parent_iter_free); > + sepol_iter_set_get_data(iter, sepol_parent_iter_get_data); > + > + > + parent->sclass.flags &= ~SEPOL_OBJECT_VISITED; > + ret = sepol_list_append(h, state->stack, parent); > + ret_goto(ret, err); > + ret = sepol_iter_next(h, iter); > + ret_goto(ret, err); > + > + return SEPOL_OK; > +err: > + sepol_parent_iter_free(h, state); > + return ret; > +} > +hidden_def(sepol_parent_traverse) > + > +char sepol_parent_isvisited(struct sepol_iter *iter) > +{ > + struct sepol_parent_traverse_state *state; > + > + state = sepol_iter_get_state(iter); > + if (state->cur_flags & SEPOL_OBJECT_VISITED) > + return 1; > + else > + return 0; > +} > +hidden_def(sepol_parent_isvisited) > + > +/* > + * SEPOL_POLICY > + */ > + > +struct sepol_policy > +{ > + struct sepol_parent sclass; > + char mls; > +}; > + > +int sepol_policy_free(struct sepol_handle *h, struct sepol_policy *o) > +{ > + intern_sepol_parent_free(SEPOL_PARENT(o)); > + free(o); > + > + return SEPOL_OK; > +} > + > +static int sepol_policy_tostring(struct sepol_handle *h, > + struct sepol_object * object __attribute__ ((unused)), > + int style, char **str) > +{ > + if (style == SEPOL_TOSTRING_DEBUG) { > + return asprintf(str, "POLICY {"); > Why are these strings hard coded? > + } else { > + *str = strdup(""); > + if (*str) > + return 0; > + else > + return -1; > + } > +} > + > +static int sepol_policy_tostring_close(struct sepol_handle *h __attribute__ ((unused)), > + struct sepol_object *object __attribute__ ((unused)), > + int style, char **str) > +{ > + if (style == SEPOL_TOSTRING_DEBUG) { > + return asprintf(str, "POLICY {"); > + } else { > + *str = strdup(""); > + if (*str) > + return 0; > + else > + return -1; > + } > +} > + > +static struct sepol_object_methods sepol_policy_methods = { > + .free = (sepol_object_free_t)sepol_policy_free, > + .tostring = sepol_policy_tostring, > + .tostring_close = sepol_policy_tostring_close > +}; > + > +int sepol_policy_create(struct sepol_handle *h, struct sepol_policy **policy) > +{ > + int ret; > + struct sepol_policy *x; > + > + *policy = NULL; > + x = calloc(1, sizeof(struct sepol_policy)); > I am adverse to calloc used on structs, this implicitly initializes the struct and makes it harder to update the initial state. Why not have an explicit initializer? > + if (x == NULL) { > + return SEPOL_ENOMEM; > + } > + > + ret = intern_sepol_parent_init(h, SEPOL_PARENT(x), SEPOL_TYPEID_POLICY, > + &sepol_policy_methods, NULL); > + ret_goto(ret, out); > + > + /* policy always has a strpool for convenience */ > + ret = sepol_object_create_strpool(h, SEPOL_OBJECT(x)); > + ret_goto(ret, out); > + > + *policy = x; > + return SEPOL_OK; > +out: > + intern_sepol_parent_free(SEPOL_PARENT(x)); > + return ret; > +} > + > +DEFINE_BOOL_PROP(policy, mls) > + > +/* > + * SEPOL_MODULE > + */ > + > +struct sepol_module > +{ > + struct sepol_parent sclass; > + char *name; > + char *version; > + char isbase; > +}; > + > +int sepol_module_free(struct sepol_handle *h, struct sepol_module *o) > +{ > + int ret; > + > + ret = intern_sepol_object_delstr(h, o, o->name); > + ret_check(ret); > + > + ret = intern_sepol_object_delstr(h, o, o->version); > + ret_check(ret); > + > + intern_sepol_parent_free(SEPOL_PARENT(o)); > + > + free(o); > + > + return SEPOL_OK; > +} > +hidden_def(sepol_module_free) > + > +static int sepol_module_tostring(struct sepol_handle *h, struct sepol_object *object, > + int style, char **str) > +{ > + struct sepol_module *module = (struct sepol_module *)object; > + > + if (module->name == NULL || module->version == NULL) > + return -1; > + > + if (style == SEPOL_TOSTRING_REFPOL) > + return asprintf(str, "policy_module(%s %s)", module->name, > So we now have 2 syntaxes for policy modules? One here and one in the lexer/parser? > + module->version); > + else > + return asprintf(str, "module %s %s;", module->name, module->version); > +} > + > +static struct sepol_object_methods sepol_module_methods = { > + .free = (sepol_object_free_t)sepol_module_free, > + .tostring = sepol_module_tostring > +}; > + > +int sepol_module_create(struct sepol_handle *h, struct sepol_module **module) > +{ > + return sepol_module_create_tree(h, module, NULL); > +} > +hidden_def(sepol_module_create) > + > +int sepol_module_create_tree(struct sepol_handle *h, struct sepol_module **module, > + struct sepol_parent *root) > +{ > + int ret; > + struct sepol_module *x; > + > + *module = NULL; > + x = calloc(1, sizeof(struct sepol_module)); > + if (x == NULL) { > + return SEPOL_ENOMEM; > + } > + > + ret = intern_sepol_parent_init(h, SEPOL_PARENT(x), SEPOL_TYPEID_MODULE, > + &sepol_module_methods, root); > + ret_goto(ret, out); > + > + *module = x; > + return SEPOL_OK; > +out: > + free(x); > + return ret; > +} > +hidden_def(sepol_module_create_tree) > + > +DEFINE_STR_PROP(module, name) > +DEFINE_STR_PROP(module, version) > +DEFINE_BOOL_PROP(module, isbase) > diff -r cacdf4377ebf -r bd4ee6e00a63 libsepol/src/policy_internal.c > --- a/libsepol/src/policy_internal.c Mon May 07 15:50:27 2007 -0400 > +++ b/libsepol/src/policy_internal.c Mon May 07 18:03:03 2007 -0400 > @@ -0,0 +1,102 @@ > +/* > + * Author : Karl MacMillan > + * > + * Copyright (C) 2007 Red Hat, Inc. > + * > + * 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_internal.h" > + > +int intern_sepol_object_init(struct sepol_handle *h, struct sepol_object *o, uint32_t typeid, > + struct sepol_object_methods *methods, struct sepol_parent *root) > +{ > + memset(o, 0, sizeof(struct sepol_object)); > + o->sclass_typeid = SEPOL_TYPEID_OBJECT; > + o->typeid = typeid; > + o->methods = methods; > + if (root && sepol_object_get_strpool(SEPOL_OBJECT(root))) > + o->strpool = sepol_object_get_strpool(SEPOL_OBJECT(root)); > + > + > + return 0; > +} > + > +void intern_sepol_object_free(struct sepol_object *o) > +{ > + if (o == NULL) > + return; > + > + if (o->flags & SEPOL_OBJECT_STRPOOL_OWNER) > + sepol_objpool_free(NULL, o->strpool); > +} > + > +int _intern_sepol_object_addstr(struct sepol_handle *h, struct sepol_object *o, char **str) > +{ > + char *tmp; > + > + tmp = strdup(*str); > + if (!tmp) > + return SEPOL_ENOMEM; > + > + *str = tmp; > + > + if (o->strpool) { > + *str = sepol_objpool_add(h, o->strpool, *str); > + if (!*str) > + return SEPOL_ENOMEM; > + } > + > + return SEPOL_OK; > +} > + > +int _intern_sepol_object_delstr(struct sepol_handle *h, struct sepol_object *o, char *str) > Why do some of these start with _ and others don't? > +{ > + int ret; > + > + if (str == NULL) > + return SEPOL_OK; > + > + if (o->strpool) { > + ret = sepol_objpool_del(h, o->strpool, str); > + return ret; > + } else { > + free(str); > + return SEPOL_OK; > + } > +} > + > +int intern_sepol_parent_init(struct sepol_handle *h, struct sepol_parent *p, uint32_t typeid, > + struct sepol_object_methods *methods, struct sepol_parent *root) > +{ > + int ret; > + > + ret = intern_sepol_object_init(h, SEPOL_OBJECT(p), typeid, methods, root); > + ret_check(ret); > + p->sclass.sclass_typeid = SEPOL_TYPEID_PARENT; > + > + ret = sepol_list_create(h, &p->children); > + if (ret < 0) > + sepol_object_free(h, SEPOL_OBJECT(p)); > + > + return ret; > +} > + > +void intern_sepol_parent_free(struct sepol_parent *p) > +{ > + intern_sepol_object_free(SEPOL_OBJECT(p)); > + > + sepol_list_free(p->children); > +} > diff -r cacdf4377ebf -r bd4ee6e00a63 libsepol/src/policy_internal.h > --- a/libsepol/src/policy_internal.h Mon May 07 15:50:27 2007 -0400 > +++ b/libsepol/src/policy_internal.h Mon May 07 18:03:03 2007 -0400 > @@ -0,0 +1,269 @@ > +#ifndef __policy_internal_h__ > +#define __policy_internal_h__ > + > +#include "dso.h" > + > +#include > +#include > +#include > + > +#include > +#include > + > +/* Internal structs and functions for the policy object system. In > + * general, policy objects cannot be created outside of the libsepol > + * tree. It is possible, but not currently implemented, so there is > + * quite a lot of internals in this header. > + * > + * One of the goals of this object system is to allow polymorphic > + * methods. That will allow calling , for example, sepol_object_free > + * on _any_ subclass of sepol_object and have the correct function > + * called for the specific subclass. This polymorphism is implemented > + * using an sepol_object_method struct for each class and a pointer to > + * that struct held in each object instance. > + * > + * A subclass is expected to create an sepol_object_methods struct > + * containing function pointers for the methods that it implements (it > + * is valid for some of the function pointers to be NULL). Every > + * instance of an sepol_object object holds a pointer to a single > + * methods struct - i.e., there is only one struct per class and every > + * instance holds a pointer to that struct. > + * > + * See sepol_object_init for how this pointer is set and sepol_object_free > + * for how subclass methods are called. > + */ > + > +/* sepol_object_free_t is the type for the free method used in the policy > + * object system. Implementations of this method should free all of the > + * memory associated with the object including the struct. > + */ > +typedef int (*sepol_object_free_t)(struct sepol_handle *h, struct sepol_object *o); > +typedef int (*sepol_object_tostring_t)(struct sepol_handle *h, struct sepol_object *o, > + int style, char **str); > + > +struct sepol_object_methods > +{ > + sepol_object_free_t free; > + sepol_object_tostring_t tostring; > + sepol_object_tostring_t tostring_close; > +}; > + > +#define SEPOL_OBJECT_STRPOOL_OWNER 1 > +#define SEPOL_OBJECT_VISITED 2 > Why aren't these in an enum? > +struct sepol_object > +{ > + struct sepol_object_methods *methods; > + struct sepol_parent *parent; > + struct sepol_objpool *strpool; > + uint32_t sclass_typeid; > What is this field? Please make it less ambiguous/confusing. > + uint32_t typeid; > + uint32_t lineno; > + char flags; > +}; > + > +/* Private initialization function for all objects. This function only > + * initializes the generic object properties - the type specific creation > + * function is responsible for initializing any type specific properties. > + * If this function fails it will clean up any memory that it allocated. The > + * calling function is responsible for any type specific memory and for freeing > + * the object struct. > + * > + * params: > + * o - object to initialize > + * typeid - typeid of o > + * methods - pointer to sepol_object_methods struct for this type. Should > + * be a pointer to a single static struct for all instances of this type. > + * root - root of the policy tree of which o is a member (may be NULL). If > + * the root is non-NULL and has a string pool then that string pool is > + * used for this object. > + */ > +int intern_sepol_object_init(struct sepol_handle *h, struct sepol_object *o, uint32_t typeid, > + struct sepol_object_methods *methods, struct sepol_parent *root); > + > +/* Free any memory associated with the super class. This should be called > + * from a type specific free function. > + */ > +void intern_sepol_object_free(struct sepol_object *o); > + > +/* Add a string to the string pool of the object. After a call to this > + * function the str pointer will point to the correct (and possibly > + * shared) version of the string to use. > + */ > +#define intern_sepol_object_addstr(h, o, str) _intern_sepol_object_addstr(h, SEPOL_OBJECT(o), str) > +int _intern_sepol_object_addstr(struct sepol_handle *h, struct sepol_object *o, char **str); > + > +/* Delete a string. If the object has a string pool the memory > + * associated with the string may not be released > + * immediately. Regardless, the caller should assume that the pointer > + * is invalid after a call to this function. > + */ > +#define intern_sepol_object_delstr(h, o, str) _intern_sepol_object_delstr(h, SEPOL_OBJECT(o), str) > +int _intern_sepol_object_delstr(struct sepol_handle *h, struct sepol_object *o, char *str); > + > +hidden_proto(sepol_typeid_tostring) > +hidden_proto(sepol_object_free) > +hidden_proto(sepol_object_create_strpool) > +hidden_proto(sepol_object_get_strpool) > +hidden_proto(sepol_object_is_strpool_owner) > +hidden_proto(sepol_object_get_typeid) > +hidden_proto(sepol_object_isinstance) > +hidden_proto(sepol_object_get_parent) > +hidden_proto(sepol_object_tostring) > +hidden_proto(sepol_object_tostring_close) > + > +struct sepol_parent > +{ > + struct sepol_object sclass; > + struct sepol_list *children; > +}; > + > +/* Initialize an sepol_parent object. Same function and general > + * properties as intern_sepol_object_init but for parent > + * objects. Objects should only call the init function for their > + * immediate parent - the parent is responsible for any further > + * chaining up the type hierarchy. > + */ > +int intern_sepol_parent_init(struct sepol_handle *h, struct sepol_parent *p, uint32_t typeid, > + struct sepol_object_methods *methods, struct sepol_parent *root); > + > +/* Internal free function for sepol_paren objects. Like the init functions > + * this chains up the type hierarchy by call inter_sepol_object_free. > + */ > +void intern_sepol_parent_free(struct sepol_parent *p); > + > +hidden_proto(sepol_parent_free_tree) > +hidden_proto(sepol_parent_append) > +hidden_proto(sepol_parent_extend) > +hidden_proto(sepol_parent_extend_list) > +hidden_proto(sepol_parent_del) > +hidden_proto(sepol_parent_insert) > +hidden_proto(sepol_parent_children) > +hidden_proto(sepol_parent_get_children) > +hidden_proto(sepol_parent_traverse) > +hidden_proto(sepol_parent_isvisited) > + > Hrm. IIRC hidden_proto is only needed if the function is going to be exported from the shared library and also used internally, are these really exported? I didn't see any map updates with this patch. > +/* sepol_policy */ > +hidden_proto(sepol_policy_free) > +hidden_proto(sepol_policy_get_mls) > +hidden_proto(sepol_policy_set_mls) > + > +/* sepol_module */ > +hidden_proto(sepol_module_free) > +hidden_proto(sepol_module_create) > +hidden_proto(sepol_module_create_tree) > +hidden_proto(sepol_module_set_name) > +hidden_proto(sepol_module_get_name) > +hidden_proto(sepol_module_set_version) > +hidden_proto(sepol_module_get_version) > +hidden_proto(sepol_module_set_isbase) > +hidden_proto(sepol_module_get_isbase) > + > + > +/* some convenience macros to check return values */ > +#define ret_check(ret) { if (ret < 0) return ret; } > +#define ret_goto(ret, tag) { if (ret < 0) goto tag; } > + > + > +/* > + * PROPERTY GENERATION MACROS > + * > + * Many of the objects are similar and will have almost identical > + * functions for getting and setting properties. These macros generate > + * those functions for brevity and correctness. > + */ > + > +/* Initialize an object set for holding strings. This should be used > + * in an object creation function to initialize a string set. This > + * handles object pooling. > I understand the argument for using these but its my experience that they make everything harder to understand like the libselinux macros.. > + */ > +#define INIT_STRSET(obj, set, ret, target) { \ > + if (SEPOL_OBJECT(obj)->strpool) { \ > + ret = sepol_objset_create(&obj->set, sepol_policy_ptrcmp); \ > + ret_goto(ret, target); \ > + } else { \ > + ret = sepol_objset_create(&obj->set, \ > + (sepol_objset_cmp_t)sepol_policy_strcmp); \ > + ret_goto(ret, target); \ > + } } > + > +#define DESTROY_STRSET(obj, set, iter, ret) { \ > + if (obj->set != NULL) { \ > + ret = sepol_iter_create(&iter); \ > + ret_check(ret); \ > + ret = sepol_objset_iter(obj->set, iter); \ > + if (ret < 0 && ret != SEPOL_ITERSTOP) return ret; \ > + while (ret == SEPOL_OK) { \ > + ret = intern_sepol_object_delstr(obj, sepol_iter_get_data(iter)); \ > + ret_check(ret); \ > + ret = sepol_iter_next(iter); \ > + } \ > + sepol_iter_destroy(iter); \ > + if (ret != SEPOL_ITERSTOP) return ret; \ > + } \ > + sepol_objset_destroy(obj->set); } > + > + > +#define DEFINE_STR_PROP(obj, prop) \ > + int sepol_##obj##_set_##prop(struct sepol_##obj *x, char *prop) \ > + { \ > + int ret; \ > + if (x-> prop ) { \ > + ret = intern_sepol_object_delstr(NULL, x, x-> prop ); \ > + ret_check(ret); \ > + } \ > + x-> prop = prop; \ > + return intern_sepol_object_addstr(NULL, x, &x-> prop ); \ > + } \ > + hidden_def(sepol_##obj##_set_##prop) \ > + const char *sepol_##obj##_get_##prop(struct sepol_##obj *x) \ > + { \ > + return x-> prop ; \ > + } \ > + hidden_def(sepol_##obj##_get_##prop) > + > +#define DEFINE_BOOL_PROP(obj, prop) \ > + int sepol_##obj##_set_##prop(struct sepol_##obj *x, char prop) \ > + { \ > + x-> prop = prop; \ > + return SEPOL_OK; \ > + } \ > + hidden_def(sepol_##obj##_set_##prop) \ > + char sepol_##obj##_get_##prop(struct sepol_##obj *x) \ > + { \ > + return x-> prop ; \ > + } \ > + hidden_def(sepol_##obj##_get_##prop) > + > +#define DEFINE_UINT_PROP(obj, prop) \ > + int sepol_##obj##_set_##prop(struct sepol_##obj *x, uint32_t prop) \ > + { \ > + x->prop = prop; \ > + return SEPOL_OK; \ > + } \ > + hidden_def(sepol_##obj##_set_##prop) \ > + uint32_t sepol_##obj##_get_##prop(struct sepol_##obj *x) \ > + { \ > + return x->prop ; \ > + } \ > + hidden_def(sepol_##obj##_get_##prop) > + > +#define DEFINE_STRSET_PROP(obj, prop, set) \ > + int sepol_##obj##_add_##prop(struct sepol_##obj *x, char *prop) \ > + { \ > + int ret; \ > + char *tmp = strdup(prop); \ > + ret = intern_sepol_object_addstr(x, &tmp); \ > + ret_check(ret); \ > + ret = sepol_objset_add(x->set, tmp); \ > + ret_check(ret); \ > + return SEPOL_OK; \ > + } \ > + hidden_def(sepol_##obj##_set_##prop) \ > + struct sepol_objset *sepol_##obj##_get_##set(struct sepol_##obj *x) \ > + { \ > + return x->set; \ > + } \ > + hidden_def(sepol_##obj##_get_##prop) > + > + > +#endif > -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with the words "unsubscribe selinux" without quotes as the message.