/* * Copyright (c) 2014 * Canonical Ltd. (All rights reserved) * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public * License published by the Free Software Foundation. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, contact Novell, Inc. or Canonical * Ltd. */ #ifndef __AA_RULE_H #define __AA_RULE_H #include #include #include "policydb.h" using namespace std; class Profile; #define RULE_NOT_SUPPORTED 0 #define RULE_ERROR -1 #define RULE_OK 1 #define RULE_TYPE_RULE 0 #define RULE_TYPE_PREFIX 1 #define RULE_TYPE_PERMS 2 // RULE_TYPE_CLASS needs to be last because various class follow it #define RULE_TYPE_CLASS 3 typedef enum { RULE_FLAG_NONE = 0, RULE_FLAG_DELETED = 1, // rule deleted - skip RULE_FLAG_MERGED = 2, // rule merged with another rule RULE_FLAG_EXPANDED = 4, // variable expanded RULE_FLAG_SUB = 8, // rule expanded to subrule(s) RULE_FLAG_IMPLIED = 16, // rule not specified in policy but // added because it is implied } rule_flags_t; class rule_t { public: int rule_type; rule_flags_t flags; rule_t(int t): rule_type(t), flags(RULE_FLAG_NONE) { } virtual ~rule_t() { }; bool is_type(int type) { return rule_type == type; } //virtual bool operator<(rule_t const &rhs)const = 0; virtual std::ostream &dump(std::ostream &os) = 0; // Follow methods in order of being called by the parse // called when profile is finished parsing virtual void post_parse_profile(Profile &prof __attribute__ ((unused))) { }; // called before final expansion of variables. So implied rules // can reference variables virtual void add_implied_rules(Profile &prof __attribute__ ((unused))) { }; // currently only called post parse // needs to change to being interatively called during parse // to support expansion in include names and profile names virtual int expand_variables(void) = 0; // called by duplicate rule merge/elimination after final expand_vars virtual bool is_mergeable(void) { return false; } virtual bool operator<(rule_t const &rhs) const { return rule_type < rhs.rule_type; } virtual bool merge(rule_t &rhs __attribute__ ((unused))) { return false; }; // called late frontend to generate data for regex backend virtual int gen_policy_re(Profile &prof) = 0; protected: const char *warned_name = NULL; virtual void warn_once(const char *name, const char *msg); virtual void warn_once(const char *name) = 0; }; std::ostream &operator<<(std::ostream &os, rule_t &rule); typedef std::list RuleList; /* Not classes so they can be used in the bison front end */ typedef uint32_t perms_t; typedef enum { AUDIT_UNSPECIFIED, AUDIT_FORCE, AUDIT_QUIET } audit_t; typedef enum { RULE_UNSPECIFIED, RULE_ALLOW, RULE_DENY } rule_mode_t; /* NOTE: we can not have a constructor for class prefixes. This is * because it will break bison, and we would need to transition to * the C++ bison bindings. Instead get around this by using a * special rule class that inherits prefixes and handles the * contruction */ class prefixes { public: audit_t audit; rule_mode_t rule_mode; int owner; ostream &dump(ostream &os) { bool output = true; switch (audit) { case AUDIT_FORCE: os << "audit"; break; case AUDIT_QUIET: os << "quiet"; break; default: output = false; } switch (rule_mode) { case RULE_DENY: if (output) os << " "; os << "deny"; output = true; break; default: break; } if (owner) { if (output) os << " "; os << "owner"; output = true; } if (output) os << " "; return os; } }; class prefix_rule_t: public rule_t, public prefixes { public: prefix_rule_t(int t = RULE_TYPE_PREFIX) : rule_t(t) { /* Must construct prefix here see note on prefixes */ audit = AUDIT_UNSPECIFIED; rule_mode = RULE_UNSPECIFIED; owner = 0; }; virtual bool valid_prefix(const prefixes &p, const char *&error) = 0; virtual bool add_prefix(const prefixes &p, const char *&error) { if (!valid_prefix(p, error)) return false; /* audit conflicts */ if (p.audit != AUDIT_UNSPECIFIED) { if (audit != AUDIT_UNSPECIFIED && audit != p.audit) { error = "conflicting audit prefix"; return false; } // audit = p.audit; } /* allow deny conflicts */ if (p.rule_mode != RULE_UNSPECIFIED) { if (rule_mode != RULE_UNSPECIFIED && rule_mode != p.rule_mode) { error = "conflicting mode prefix"; return false; } rule_mode = p.rule_mode; } /* owner !owner conflicts */ if (p.owner) { if (owner && owner != p.owner) { error = "conflicting owner prefix"; return false; } owner = p.owner; } /* does the prefix imply a modifier */ if (p.rule_mode == RULE_DENY && p.audit == AUDIT_FORCE) { rule_mode = RULE_DENY; } else if (p.rule_mode == RULE_DENY) { rule_mode = RULE_DENY; audit = AUDIT_FORCE; } else if (p.audit != AUDIT_UNSPECIFIED) { audit = p.audit; } return true; } virtual bool operator<(prefixes const &rhs) const { if ((uint) audit < (uint) rhs.audit) return true; if ((uint) rule_mode < (uint) rhs.rule_mode) return true; if (owner < rhs.owner) return true; return false; } virtual bool operator<(prefix_rule_t const &rhs) const { if (rule_type < rhs.rule_type) return true; if (rhs.rule_type < rule_type) return false; return *this < (prefixes const &)rhs; } virtual ostream &dump(ostream &os) { prefixes::dump(os); return os; } }; /* NOTE: rule_type is RULE_TYPE_CLASS + AA_CLASS */ class class_rule_t: public prefix_rule_t { public: class_rule_t(int c): prefix_rule_t(RULE_TYPE_CLASS + c) { } int aa_class(void) { return rule_type - RULE_TYPE_CLASS; } virtual ostream &dump(ostream &os) { prefix_rule_t::dump(os); os << aa_class_table[aa_class()]; return os; } }; class perms_rule_t: public class_rule_t { public: perms_rule_t(int c): class_rule_t(c), perms(0) { }; /* defaut perms, override/mask off if none default used */ virtual ostream &dump(ostream &os) { return os; } perms_t perms; }; #endif /* __AA_RULE_H */