From: <ssm...@us...> - 2007-02-05 19:01:33
|
Revision: 2220 http://svn.sourceforge.net/selinux/?rev=2220&view=rev Author: ssmalley Date: 2007-02-05 11:01:07 -0800 (Mon, 05 Feb 2007) Log Message: ----------- Author: Karl MacMillan Email: kma...@me... Subject: add sepolgen Date: Wed, 31 Jan 2007 11:43:14 -0500 The patch at [1] adds the sepolgen python library for policy generation and a new implementation of audit2allow based on this library. The library has facilities for: * parsing audit messages * parsing and representing policy (including refpolicy interfaces) * manipulating / transforming policy (e.g., adding require statements) * generating policy from access requests / audit messages (including calls to refpolicy interfaces) * outputting policy as text * compiling policy modules All of the requested updates from the previous review have been made. Notes for packaging: * This adds a new dependency between policycoreutils and sepolgen * The tool sepolgen-ifgen needs to be run to extract information from the reference policy headers for audit2allow to generate refpolicy. The rpm spec file at http://hg.et.redhat.com/selinux/madison?f=b26375c7641a;file=madison.spec shows how I did this. * Audit2allow currently has a few regressions from the old version. This will be fixed soon. [1] http://people.redhat.com/kmacmill/patches/selinux/sepolgen-initial-submission.patch.gz Signed-off-by: Karl MacMillan <kma...@me...> Modified Paths: -------------- trunk/Makefile trunk/policycoreutils/ChangeLog trunk/policycoreutils/VERSION trunk/policycoreutils/audit2allow/Makefile trunk/policycoreutils/audit2allow/audit2allow Added Paths: ----------- trunk/policycoreutils/audit2allow/sepolgen-ifgen trunk/sepolgen/ trunk/sepolgen/COPYING trunk/sepolgen/HACKING trunk/sepolgen/Makefile trunk/sepolgen/VERSION trunk/sepolgen/src/ trunk/sepolgen/src/Makefile trunk/sepolgen/src/sepolgen/ trunk/sepolgen/src/sepolgen/Makefile trunk/sepolgen/src/sepolgen/__init__.py trunk/sepolgen/src/sepolgen/access.py trunk/sepolgen/src/sepolgen/audit.py trunk/sepolgen/src/sepolgen/classperms.py trunk/sepolgen/src/sepolgen/defaults.py trunk/sepolgen/src/sepolgen/interfaces.py trunk/sepolgen/src/sepolgen/lex.py trunk/sepolgen/src/sepolgen/matching.py trunk/sepolgen/src/sepolgen/module.py trunk/sepolgen/src/sepolgen/objectmodel.py trunk/sepolgen/src/sepolgen/output.py trunk/sepolgen/src/sepolgen/policygen.py trunk/sepolgen/src/sepolgen/refparser.py trunk/sepolgen/src/sepolgen/refpolicy.py trunk/sepolgen/src/sepolgen/sepolgeni18n.py trunk/sepolgen/src/sepolgen/util.py trunk/sepolgen/src/sepolgen/yacc.py trunk/sepolgen/src/share/ trunk/sepolgen/src/share/Makefile trunk/sepolgen/src/share/perm_map trunk/sepolgen/tests/ trunk/sepolgen/tests/Makefile trunk/sepolgen/tests/audit.txt trunk/sepolgen/tests/module_compile_test.te trunk/sepolgen/tests/perm_map trunk/sepolgen/tests/run-tests.py trunk/sepolgen/tests/test_access.py trunk/sepolgen/tests/test_audit.py trunk/sepolgen/tests/test_data/ trunk/sepolgen/tests/test_data/audit.log trunk/sepolgen/tests/test_data/httpd.log trunk/sepolgen/tests/test_data/short.log trunk/sepolgen/tests/test_interfaces.py trunk/sepolgen/tests/test_matching.py trunk/sepolgen/tests/test_module.py trunk/sepolgen/tests/test_objectmodel.py trunk/sepolgen/tests/test_policygen.py trunk/sepolgen/tests/test_refparser.py trunk/sepolgen/tests/test_refpolicy.py Removed Paths: ------------- trunk/policycoreutils/audit2allow/avc.py Modified: trunk/Makefile =================================================================== --- trunk/Makefile 2007-02-05 18:01:59 UTC (rev 2219) +++ trunk/Makefile 2007-02-05 19:01:07 UTC (rev 2220) @@ -1,4 +1,4 @@ -SUBDIRS=libsepol libselinux libsemanage checkpolicy policycoreutils # policy +SUBDIRS=libsepol libselinux libsemanage sepolgen checkpolicy policycoreutils # policy PYSUBDIRS=libselinux libsemanage ifeq ($(DEBUG),1) Modified: trunk/policycoreutils/ChangeLog =================================================================== --- trunk/policycoreutils/ChangeLog 2007-02-05 18:01:59 UTC (rev 2219) +++ trunk/policycoreutils/ChangeLog 2007-02-05 19:01:07 UTC (rev 2220) @@ -1,3 +1,9 @@ +2.0.0 2007-02-05 + * Merged new audit2allow from Karl MacMillan. + This audit2allow depends on the new sepolgen python module. + Note that you must run the sepolgen-ifgen tool to generate + the data needed by audit2allow to generate refpolicy. + 1.34.1 2007-01-22 * Fixed newrole non-pam build. Modified: trunk/policycoreutils/VERSION =================================================================== --- trunk/policycoreutils/VERSION 2007-02-05 18:01:59 UTC (rev 2219) +++ trunk/policycoreutils/VERSION 2007-02-05 19:01:07 UTC (rev 2220) @@ -1 +1 @@ -1.34.1 +2.0.0 Modified: trunk/policycoreutils/audit2allow/Makefile =================================================================== --- trunk/policycoreutils/audit2allow/Makefile 2007-02-05 18:01:59 UTC (rev 2219) +++ trunk/policycoreutils/audit2allow/Makefile 2007-02-05 19:01:07 UTC (rev 2220) @@ -4,23 +4,19 @@ LIBDIR ?= $(PREFIX)/lib MANDIR ?= $(PREFIX)/share/man LOCALEDIR ?= /usr/share/locale -PYLIBVER ?= $(shell python -c 'import sys;print "python%d.%d" % sys.version_info[0:2]') -PYTHONLIBDIR ?= $(LIBDIR)/$(PYLIBVER) -TARGETS=audit2allow +all: ; -all: $(TARGETS) - install: all -mkdir -p $(BINDIR) - install -m 755 $(TARGETS) $(BINDIR) + install -m 755 audit2allow $(BINDIR) + install -m 755 sepolgen-ifgen $(BINDIR) -mkdir -p $(MANDIR)/man1 install -m 644 audit2allow.1 $(MANDIR)/man1/ - test -d $(PYTHONLIBDIR)/site-packages || install -m 755 -d $(PYTHONLIBDIR)/site-packages - install -m 755 avc.py $(PYTHONLIBDIR)/site-packages clean: + rm -f *~ -indent: +indent: ; -relabel: +relabel: ; Modified: trunk/policycoreutils/audit2allow/audit2allow =================================================================== --- trunk/policycoreutils/audit2allow/audit2allow 2007-02-05 18:01:59 UTC (rev 2219) +++ trunk/policycoreutils/audit2allow/audit2allow 2007-02-05 19:01:07 UTC (rev 2220) @@ -1,226 +1,268 @@ #! /usr/bin/python -E -# Copyright (C) 2005 Red Hat +# Authors: Karl MacMillan <kma...@me...> +# +# Copyright (C) 2006 Red Hat # see file 'COPYING' for use and warranty information # -# Audit2allow is a rewrite of prior perl script. +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; version 2 only # -# Based off original audit2allow perl script: which credits -# newrules.pl, Copyright (C) 2001 Justin R. Smith (js...@mc...) -# 2003 Oct 11: Add -l option by Yuichi Nakamura(yn...@us...) +# 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. # -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; either version 2 of -# the License, or (at your option) any later version. +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # -# 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, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA -# 02111-1307 USA -# -# -from avc import * -if __name__ == '__main__': - import commands, sys, os, getopt, selinux - import gettext - import re +import sys +import tempfile + +import sepolgen.audit as audit +import sepolgen.policygen as policygen +import sepolgen.interfaces as interfaces +import sepolgen.output as output +import sepolgen.objectmodel as objectmodel +import sepolgen.defaults as defaults +import sepolgen.module as module +from sepolgen.sepolgeni18n import _ + +class AuditToPolicy: + VERSION = "%prog .1" + SYSLOG = "/var/log/messages" + + def __init__(self): + self.__options = None + self.__parser = None + self.__avs = None + + def __parse_options(self): + from optparse import OptionParser + + parser = OptionParser(version=self.VERSION) + parser.add_option("-a", "--audit", action="store_true", dest="audit", default=False, + help="read input from audit log - conflicts with -i") + parser.add_option("-d", "--dmesg", action="store_true", dest="dmesg", default=False, + help="read input from dmesg - conflicts with --audit and --input") + parser.add_option("-i", "--input", dest="input", + help="read input from <input> - conflicts with -a") + parser.add_option("-l", "--lastreload", action="store_true", dest="lastreload", default=False, + help="read input only after the last reload") + parser.add_option("-r", "--requires", action="store_true", dest="requires", default=False, + help="generate require statements for rules") + parser.add_option("-m", "--module", dest="module", + help="set the module name - implies --requires") + parser.add_option("-M", "--module-package", dest="module_package", + help="generate a module package - conflicts with -o and -m") + parser.add_option("-o", "--output", dest="output", + help="append output to <filename>, conflicts with -M") + parser.add_option("-R", "--reference", action="store_true", dest="refpolicy", + default=False, help="generate refpolicy style output") + parser.add_option("-v", "--verbose", action="store_true", dest="verbose", + default=False, help="explain generated output") + parser.add_option("-e", "--explain", action="store_true", dest="explain_long", + default=False, help="fully explain generated output") + parser.add_option("-t", "--type", help="only process messages with a type that matches this regex", + dest="type") + parser.add_option("--perm-map", dest="perm_map", help="file name of perm map") + parser.add_option("--interface-info", dest="interface_info", help="file name of interface information") + parser.add_option("--debug", dest="debug", action="store_true", default=False, + help="leave generated modules for -M") + + options, args = parser.parse_args() + + # Make -d, -a, and -i conflict + if options.audit is True: + if options.input is not None: + sys.stderr.write("error: --audit conflicts with --input\n") + if options.dmesg is True: + sys.stderr.write("error: --audit conflicts with --dmesg\n") + if options.input is not None and options.dmesg is True: + sys.stderr.write("error: --input conflicts with --dmesg\n") + + # Turn on requires generation if a module name is given. Also verify + # the module name. + if options.module: + name = options.module + else: + name = options.module_package + if name: + options.requires = True + if not module.is_valid_name(name): + sys.stderr.write("only letters and numbers allowed in module names\n") + sys.exit(2) + + + # Make -M and -o conflict + if options.module_package: + if options.output: + sys.stderr.write("error: --module-package conflicts with --output\n") + sys.exit(2) + if options.module: + sys.stderr.write("error: --module-package conflicts with --module\n") + sys.exit(2) + + self.__options = options + + def __read_input(self): + parser = audit.AuditParser(last_load_only=self.__options.lastreload) + + filename = None + messages = None + f = None + + # Figure out what input we want + if self.__options.input is not None: + filename = self.__options.input + elif self.__options.dmesg: + messages = audit.get_dmesg_msgs() + elif self.__options.audit: + try: + messages = audit.get_audit_msgs() + except OSError, e: + sys.stderr.write('could not run ausearch - "%s"\n' % str(e)) + sys.exit(1) + else: + # This is the default if no input is specified + f = sys.stdin + + # Get the input + if filename is not None: + try: + f = open(filename) + except IOError, e: + sys.stderr.write('could not open file %s - "%s"\n' % (filename, str(e))) + sys.exit(1) + + if f is not None: + parser.parse_file(f) + f.close() + + if messages is not None: + parser.parse_string(messages) + + self.__parser = parser + + def __process_input(self): + if self.__options.type: + filter = audit.TypeFilter(self.__options.type) + self.__avs = self.__parser.to_access(filter) + else: + self.__avs = self.__parser.to_access() + + def __load_interface_info(self): + # Load interface info file + if self.__options.interface_info: + fn = self.__options.interface_info + else: + fn = defaults.interface_info() try: - gettext.install('policycoreutils') + fd = open(fn) except: - pass - def get_mls_flag(): - if selinux.is_selinux_mls_enabled(): - return "-M" - else: - return "" + sys.stderr.write("could not open interface info [%s]\n" % fn) + sys.exit(1) - def usage(msg = ""): - print _('audit2allow [-adhilrv] [-t file ] [ -f fcfile ] [-i <inputfile> ] [[-m|-M] <modulename> ] [-o <outputfile>]\n\ - -a, --all read input from audit and message log, conflicts with -i\n\ - -d, --dmesg read input from output of /bin/dmesg\n\ - -h, --help display this message\n\ - -i, --input read input from <inputfile> conflicts with -a\n\ - -l, --lastreload read input only after last \"load_policy\"\n\ - -m, --module generate module/require output <modulename> \n\ - -M generate loadable module package, conflicts with -o\n\ - -o, --output append output to <outputfile>, conflicts with -M\n\ - -r, --requires generate require output \n\ - -t, --tefile Add input from Existing Type Enforcement file\n\ - -f, --fcfile Existing Type Enforcement file, requires -M\n\ - -v, --verbose verbose output\n\ - -A, --analyze Analyze output\n\ - ') - if msg != "": - print msg - sys.exit(1) - - def verify_module(module): - m = re.findall("[^a-zA-Z0-9]", module) - if len(m) != 0: - usage(_("Alphanumeric Charaters Only")) - - def errorExit(error): - sys.stderr.write("%s: " % sys.argv[0]) - sys.stderr.write("%s\n" % error) - sys.stderr.flush() - sys.exit(1) + ifs = interfaces.InterfaceSet() + ifs.from_file(fd) + fd.close() - # - # - # - try: - last_reload = 0 - inputfd = sys.stdin - output = sys.stdout - module = "" - requires = 0 - verbose = 0 - auditlogs = 0 - buildPP = 0 - input_ind = 0 - output_ind = 0 - ref_ind = False - analyze = False - te_inputs = [] + # Also load perm maps + if self.__options.perm_map: + fn = self.__options.perm_map + else: + fn = defaults.perm_map() + try: + fd = open(fn) + except: + sys.stderr.write("could not open perm map [%s]\n" % fn) + sys.exit(1) - fc_file = "" - gopts, cmds = getopt.getopt(sys.argv[1:], - 'Aadf:hi:lm:M:o:rt:vR', - ['all', - 'analyze', - 'dmesg', - 'fcfile=', - 'help', - 'input=', - 'lastreload', - 'module=', - 'output=', - 'requires', - 'reference', - 'tefile=', - 'verbose' - ]) - for o,a in gopts: - if o == "-a" or o == "--all": - if input_ind: - usage() - inputfd = open("/var/log/messages", "r") - auditlogs = 1 - if o == "-d" or o == "--dmesg": - inputfd = os.popen("/bin/dmesg", "r") - if o == "-f" or o == "--fcfile": - if a[0] == "-": - usage() - fc_file = a - if o == "-h" or o == "--help": - usage() - if o == "-i"or o == "--input": - if auditlogs or a[0] == "-": - usage() - input_ind = 1 - inputfd = open(a, "r") - if o == '--lastreload' or o == "-l": - last_reload = 1 - if o == "-m" or o == "--module": - if module != "" or a[0] == "-": - usage() - module = a - verify_module(module) - if o == "-M": - if module != "" or output_ind or a[0] == "-": - usage() - module = a - verify_module(module) - outfile = a+".te" - buildPP = 1 - if not os.path.exists("/usr/bin/checkmodule"): - errorExit("-M Requires the checkmodule command, you need to install the checkpolicy rpm package") - output = open(outfile, "w") - if o == "-r" or o == "--requires": - requires = 1 - if o == "-t" or o == "--tefile": - te_inputs.append(open(a, "r")) - - if o == "-R" or o == "--reference": - ref_ind = True - - if o == "-o" or o == "--output": - if module != "" or a[0] == "-": - usage() - output = open(a, "a") - output_ind = 1 - if o == "-v" or o == "--verbose": - verbose = 1 - - if o == "-A" or o == "--analyze": - analyze = True - - if len(cmds) != 0: - usage() + perm_maps = objectmodel.PermMappings() + perm_maps.from_file(fd) + + return (ifs, perm_maps) + + + def __output(self): + g = policygen.PolicyGenerator() + + if self.__options.module: + g.set_module_name(self.__options.module) + + # Interface generation + if self.__options.refpolicy: + ifs, perm_maps = self.__load_interface_info() + g.set_gen_refpol(ifs, perm_maps) - if fc_file != "" and not buildPP: - usage("Error %s: Option -fc requires -M" % sys.argv[0]) - - serules = SERules(last_reload, verbose) + # Explanation + if self.__options.verbose: + g.set_gen_explain(policygen.SHORT_EXPLANATION) + if self.__options.explain_long: + g.set_gen_explain(policygen.LONG_EXPLANATION) - for i in te_inputs: - te = TERules(serules) - te.load(i) + # Requires + if self.__options.requires: + g.set_gen_requires(True) - serules.load(inputfd) + # Generate the policy + g.add_access(self.__avs) + # Output + writer = output.ModuleWriter() - if ref_ind: - serules.gen_reference_policy() + # Module package + if self.__options.module_package: + g.set_module_name(self.__options.module_package) - if analyze: - serules.analyze() - sys.exit(0) + fd = tempfile.NamedTemporaryFile() + writer.write(g.get_module(), fd) + fd.flush() + + mc = module.ModuleCompiler() + if self.__options.debug: + clean = False + else: + clean = True - if auditlogs and os.path.exists("/var/log/audit/audit.log"): - inputfd = os.popen("ausearch -m avc,MAC_POLICY_LOAD") - serules.load(inputfd) + if self.__options.refpolicy: + mc.refpolicy = True + + try: + mc.create_module_package(fd.name, self.__options.module_package + ".pp", + cleanup=clean) + except RuntimeError, e: + print e + sys.exit(1) - if buildPP: - print (_("Generating type enforcment file: %s.te") % module) - output.write(serules.out(requires, module)) - output.flush() - if buildPP: - if ref_ind: - rc, type = selinux.selinux_getpolicytype() - cmd = "make -f /usr/share/selinux/%s/include/Makefile %s.pp" % (type, module) - print _("Compiling policy") - print cmd - rc = commands.getstatusoutput(cmd) - else: - cmd = "checkmodule %s -m -o %s.mod %s.te" % (get_mls_flag(), module, module) - print _("Compiling policy") - print cmd - rc = commands.getstatusoutput(cmd) - if rc[0] == 0: - cmd = "semodule_package -o %s.pp -m %s.mod" % (module, module) - if fc_file != "": - cmd = "%s -f %s" % (cmd, fc_file) - - print cmd - rc = commands.getstatusoutput(cmd) - if rc[0] == 0: - print _("\n******************** IMPORTANT ***********************\n") - print (_("In order to load this newly created policy package into the kernel,\nyou are required to execute \n\nsemodule -i %s.pp\n\n") % module) - else: - errorExit(rc[1]) + # This should unlink the temporary file + fd.close() + sys.stdout.write(_("******************** IMPORTANT ***********************\n")) + sys.stdout.write((_("To make this policy package active, execute:" +\ + "\n\nsemodule -i %s.pp\n\n") % self.__options.module_package)) + + else: + # File or stdout + if self.__options.module: + g.set_module_name(self.__options.module) - except getopt.error, error: - errorExit(_("Options Error: %s ") % error.msg) - except ValueError, error: - errorExit(error.args[0]) - except IOError, error: - errorExit(error) - except KeyboardInterrupt, error: - sys.exit(0) + if self.__options.output: + fd = open(self.__options.output, "w") + else: + fd = sys.stdout + writer.write(g.get_module(), fd) + + def main(self): + try: + self.__parse_options() + self.__read_input() + self.__process_input() + self.__output() + except KeyboardInterrupt: + sys.exit(0) + +if __name__ == "__main__": + app = AuditToPolicy() + app.main() Deleted: trunk/policycoreutils/audit2allow/avc.py =================================================================== --- trunk/policycoreutils/audit2allow/avc.py 2007-02-05 18:01:59 UTC (rev 2219) +++ trunk/policycoreutils/audit2allow/avc.py 2007-02-05 19:01:07 UTC (rev 2220) @@ -1,553 +0,0 @@ -#! /usr/bin/python -E -# Copyright (C) 2006 Red Hat -# see file 'COPYING' for use and warranty information -# -# avc.py is a plugin modules used by audit2allow and other objects to process -# avc messages from the log files -# -# Based off original audit2allow perl script: which credits -# newrules.pl, Copyright (C) 2001 Justin R. Smith (js...@mc...) -# 2003 Oct 11: Add -l option by Yuichi Nakamura(yn...@us...) -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; either version 2 of -# the License, or (at your option) any later version. -# -# 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, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA -# 02111-1307 USA -# -# -import sys, os, pwd, string, re, selinux - -obj = "(\{[^\}]*\}|[^ \t:]*)" -allow_regexp = "(allow|dontaudit)[ \t]+%s[ \t]*%s[ \t]*:[ \t]*%s[ \t]*%s" % (obj, obj, obj, obj) -awk_script = '/^[[:blank:]]*interface[[:blank:]]*\(/ {\n\ - IFACEFILE=FILENAME\n\ - IFACENAME = gensub("^[[:blank:]]*interface[[:blank:]]*\\\\(\`?","","g",$0);\n\ - IFACENAME = gensub("\'?,.*$","","g",IFACENAME);\n\ -}\n\ -\n\ -/^[[:blank:]]*(allow|dontaudit)[[:blank:]]+.*;[[:blank:]]*$/ {\n\ -\n\ - if ((length(IFACENAME) > 0) && (IFACEFILE == FILENAME)){\n\ - ALLOW = gensub("^[[:blank:]]*","","g",$0)\n\ - ALLOW = gensub(";[[:blank:]]*$","","g",$0)\n\ - print FILENAME "\\t" IFACENAME "\\t" ALLOW;\n\ - }\n\ -}\ -' - -class context: - def __init__(self, scontext): - self.scontext = scontext - con=scontext.split(":") - self.user = con[0] - self.role = con[1] - self.type = con[2] - if len(con) > 3: - self.mls = con[3] - else: - self.mls = "s0" - - def __str__(self): - return self.scontext - -class accessTrans: - def __init__(self): - self.dict = {} - try: - fd = open("/usr/share/selinux/devel/include/support/obj_perm_sets.spt") - except IOError, error: - raise IOError("Reference policy generation requires the policy development package selinux-policy-devel.\n%s" % error) - records = fd.read().split("\n") - regexp = "^define *\(`([^']*)' *, *` *\{([^}]*)}'" - for r in records: - m = re.match(regexp,r) - if m != None: - self.dict[m.groups()[0]] = m.groups()[1].split() - fd.close() - def get(self, var): - l = [] - for v in var: - if v in self.dict.keys(): - l += self.dict[v] - else: - if v not in ("{", "}"): - l.append(v) - return l - -class interfaces: - def __init__(self): - self.dict = {} - trans = accessTrans() - (input, output) = os.popen2("awk -f - /usr/share/selinux/devel/include/*/*.if 2> /dev/null") - input.write(awk_script) - input.close() - records = output.read().split("\n") - input.close() - if len(records) > 0: - regexp = "([^ \t]*)[ \t]+([^ \t]*)[ \t]+%s" % allow_regexp - for r in records: - m = re.match(regexp,r) - if m == None: - continue - val = m.groups() - file = os.path.basename(val[0]).split(".")[0] - iface = val[1] - Scon = val[3].split() - Tcon = val[4].split() - Class = val[5].split() - Access = trans.get(val[6].split()) - for s in Scon: - for t in Tcon: - for c in Class: - if (s, t, c) not in self.dict.keys(): - self.dict[(s, t, c)] = [] - self.dict[(s, t, c)].append((Access, file, iface)) - def out(self): - keys = self.dict.keys() - keys.sort() - for k in keys: - print k - for i in self.dict[k]: - print "\t", i - - def match(self, Scon, Tcon, Class, Access): - keys = self.dict.keys() - ret = [] - if (Scon, Tcon, Class) in keys: - for i in self.dict[(Scon, Tcon, Class)]: - if Access in i[0]: - if i[2].find(Access) >= 0: - ret.insert(0, i) - else: - ret.append(i) - return ret - if ("$1", Tcon, Class) in keys: - for i in self.dict[("$1", Tcon, Class)]: - if Access in i[0]: - if i[2].find(Access) >= 0: - ret.insert(0, i) - else: - ret.append(i) - return ret - if (Scon, "$1", Class) in keys: - for i in self.dict[(Scon, "$1", Class)]: - if Access in i[0]: - if i[2].find(Access) >= 0: - ret.insert(0, i) - else: - ret.append(i) - return ret - else: - return ret - -import glob, imp -pluginPath = "/usr/share/selinux/plugins" -if not pluginPath in sys.path: - sys.path.append(pluginPath) - -class Analyze: - def __init__(self): - self.plugins = [] - for p in glob.glob("/usr/share/selinux/plugins/*.py"): - plugin = os.path.basename(p)[:-3] - self.plugins.append(imp.load_module(plugin, *imp.find_module(plugin))) - - def process(self, AVCS): - ret = [] - avcs = AVCS - for p in self.plugins: - if avcs == None: - break; - r = p.analyze(avcs) - if len(r) == 0: - continue - avcs = r[1] - if len(r[0]) > 0: - ret.append(r[0]) - return ret - -class serule: - def __init__(self, key): - self.type = key[0] - self.source = key[1] - self.target = key[2] - self.seclass = key[3] - self.access = [] - self.avcinfo = {} - self.iface = None - - def add(self, avc): - for a in avc[0]: - if a not in self.avcinfo.keys(): - self.avcinfo[a] = [] - self.access.append(a) - self.avcinfo[a].append(avc[1:]) - - def getAccess(self): - if len(self.access) == 1: - return self.access[0] - else: - self.access.sort() - return "{ " + string.join(self.access) +" }" - - def getName(self): - print self.avcinfo - - def out(self, verbose = 0): - ret = "" - ret = ret+"%s %s %s:%s %s;" % (self.type, self.source, self.gettarget(), self.seclass, self.getAccess()) - if verbose: - keys = self.avcinfo.keys() - keys.sort() - for i in keys: - for x in self.avcinfo[i]: - ret = ret+"\n\t#TYPE=AVC MSG=%s " % x[0] - if len(x[1]): - ret=ret+"COMM=%s " % x[1] - if len(x[2]): - ret=ret+"NAME=%s " % x[2] - ret = ret + " : " + i - return ret - - def gen_reference_policy(self, iface): - ret = "" - Scon = self.source - Tcon = self.gettarget() - Class = self.seclass - Access = self.getAccess() - m = iface.match(Scon,Tcon,Class,Access) - if len(m) == 0: - return self.out() - else: - file = m[0][1] - ret = "\n#%s\n"% self.out() - ret += "optional_policy(`\n" - first = True - for i in m: - if file != i[1]: - ret += "')\ngen_require(`%s', `\n" % i[1] - file = i[1] - first = True - if first: - ret += "\t%s(%s)\n" % (i[2], Scon) - first = False - else: - ret += "#\t%s(%s)\n" % (i[2], Scon) - ret += "');" - return ret - - def gettarget(self): - if self.source == self.target: - return "self" - else: - return self.target - -def warning(error): - sys.stderr.write("%s: " % sys.argv[0]) - sys.stderr.write("%s\n" % error) - sys.stderr.flush() - - -class TERules: - def __init__(self, serules): - self.VALID_CMDS = ("allow", "dontaudit", "auditallow") - self.serules = serules - - def load(self, input): - line = input.readline() - while line: - rec = line.split() - if len(rec) and rec[0] in self.VALID_CMDS: - self.add_terule(line) - line = input.readline() - - def add_terule(self, rule): - rc = rule.split(":") - rules = rc[0].split() - type = rules[0] - (sources, targets) = self.rules_split(rules[1:]) - rules = rc[1].split() - (classes, access) = self.rules_split(rules) - for scon in sources: - for tcon in targets: - for seclass in classes: - self.serules.add_rule(type, scon, tcon, seclass,access) - - def rules_split(self, rules): - (idx, target ) = self.get_target(0, rules) - (idx, subject) = self.get_target(idx, rules) - return (target, subject) - - def get_target(self, i, rule): - target = [] - if rule[i][0] == "{": - for t in rule[i].split("{"): - if len(t): - target.append(t) - i = i+1 - for s in rule[i:]: - if s.find("}") >= 0: - for s1 in s.split("}"): - if len(s1): - target.append(s1) - i = i+1 - return (i, target) - - target.append(s) - i = i+1 - else: - if rule[i].find(";") >= 0: - for s1 in rule[i].split(";"): - if len(s1): - target.append(s1) - else: - target.append(rule[i]) - - i = i+1 - return (i, target) - - -ALLOW = 0 -STYPE = 1 -TTYPE = 2 -CLASS = 3 -COMM = 1 -NAME = 3 - -class SERules: - def __init__(self, last_reload = 0, verbose = 0): - self.last_reload = last_reload - self.initialize() - self.gen_ref_policy = False - self.verbose = verbose - self.AVCS = [] - self.INVALID_SIDS = {} - - def initialize(self): - self.seRules = {} - self.classes = {} - self.types = [] - self.roles = [] - - def load(self, input): - dict = [] - found = 0 - line = input.readline() - while line: - rec = line.split() - for i in rec: - if i == "avc:" or i == "message=avc:" or i == "msg='avc:": - found = 1 - else: - if i == "security_compute_sid:": - self.security_compute_sid(rec) - found = 1 - elif i == "type=MAC_POLICY_LOAD" and self.last_reload: - self.initialize() - break - else: - dict.append(i) - - if not found: - regexp = "audit\(\d+\.\d+:\d+\): policy loaded" - m = re.match(regexp, line) - if m !=None: - found =1 - dict.append("load_policy") - dict.append("granted") - - if found: - self.translate(dict) - found = 0 - dict = [] - line = input.readline() - - - def translate(self,dict): - AVC = {} - AVC["access"] = [] - if "load_policy" in dict and self.last_reload: - self.initialize() - - if "granted" in dict: - return - try: - for i in range (0, len(dict)): - if dict[i] == "{": - i = i+1 - while i<len(dict) and dict[i] != "}": - AVC["access"].append(dict[i]) - i = i+1 - continue - - t = dict[i].split('=') - if len(t) < 2: - continue - AVC[t[0]] = t[1] - - for i in ("scontext", "tcontext", "tclass"): - if i not in AVC.keys(): - return - if len(AVC["access"]) == 0: - return - - except IndexError, e: - warning("Bad AVC Line: %s" % avc) - return - - self.add_allow(AVC) - - def security_compute_sid(self, rec): - dict={} - for i in rec: - t = i.split('=') - if len(t) < 2: - continue - dict[t[0]]=t[1] - try: - r = context(dict["scontext"]).role - t = context(dict["tcontext"]).type - self.add_type(t) - self.add_role(r) - self.INVALID_SIDS[(r,t)]=rec - except: - return - - def add_avc(self, AVC): - for a in self.AVCS: - if a["tclass"] == AVC["tclass"] and a["access"] == AVC["access"] and a["tcontext"] == AVC["tcontext"] and a["scontext"] == AVC["scontext"] and a["comm"] == AVC["comm"] and a["name"] == AVC["name"]: - return - self.AVCS.append(AVC) - - def add_rule(self, rule_type, scon, tcon, tclass, access, msg = "", comm = "", name = ""): - AVC = {} - AVC["tclass"] = tclass - AVC["access"] = access - AVC["tcon"] = tcon - AVC["scon"] = scon - AVC["comm"] = comm - AVC["name"] = name - self.add_avc(AVC) - - self.add_class(tclass, access) - self.add_type(tcon) - self.add_type(scon) - key = (rule_type, scon, tcon, seclass) - if key not in self.seRules.keys(): - self.seRules[key] = serule(key) - self.seRules[key].add((access, msg, comm, name )) - - def add_allow(self, AVC): - self.add_class(AVC["tclass"], AVC["access"]) - tcontext = context(AVC["tcontext"]) - scontext = context(AVC["scontext"]) - - self.add_type(tcontext.type) - self.add_type(scontext.type) - - self.add_role(scontext.role) - - key = ("allow", scontext.type, tcontext.type, AVC["tclass"]) - if key not in self.seRules.keys(): - self.seRules[key] = serule(key) - - avckeys = AVC.keys() - for i in ( "name", "comm", "msg" ): - if i not in avckeys: - AVC[i] = "" - - self.add_avc(AVC) - self.seRules[key].add((AVC["access"], AVC["msg"], AVC["comm"], AVC["name"])) - - def add_class(self,seclass, access): - if seclass not in self.classes.keys(): - self.classes[seclass] = [] - for a in access: - if a not in self.classes[seclass]: - self.classes[seclass].append(a) - - def add_role(self,role): - if role not in self.roles: - self.roles.append(role) - - def add_type(self,type): - if type not in self.types: - self.types.append(type) - - def gen_reference_policy(self): - self.gen_ref_policy = True - self.iface = interfaces() - - def gen_module(self, module): - if self.gen_ref_policy: - return "policy_module(%s, 1.0);" % module - else: - return "module %s 1.0;" % module - - def gen_requires(self): - self.roles.sort() - self.types.sort() - keys = self.classes.keys() - keys.sort() - rec = "\n\nrequire {\n" - if not self.gen_ref_policy: - for i in keys: - access = self.classes[i] - if len(access) > 1: - access.sort() - rec += "\tclass %s {" % i - for a in access: - rec += " %s" % a - rec += " }; \n" - else: - rec += "\tclass %s %s;\n" % (i, access[0]) - - for i in self.types: - rec += "\ttype %s; \n" % i - - if not self.gen_ref_policy: - for i in self.roles: - rec += "\trole %s; \n" % i - - rec += "};\n\n" - return rec - - def analyze(self): - a = Analyze() - for i in a.process(self.AVCS): - print i[0][0] - print "" - - def out(self, require = 0, module = ""): - rec = "" - if len(self.seRules.keys()) == 0 and len(self.INVALID_SIDS) == 0: - raise(ValueError("No AVC messages found.")) - if module != "": - rec += self.gen_module(module) - rec += self.gen_requires() - else: - if require: - rec+=self.gen_requires() - - for i in self.INVALID_SIDS.keys(): - rec += "role %s types %s;\n" % i - - keys = self.seRules.keys() - keys.sort() - for i in keys: - if self.gen_ref_policy: - rec += self.seRules[i].gen_reference_policy(self.iface)+"\n" - else: - rec += self.seRules[i].out(self.verbose)+"\n" - return rec - Added: trunk/policycoreutils/audit2allow/sepolgen-ifgen =================================================================== --- trunk/policycoreutils/audit2allow/sepolgen-ifgen (rev 0) +++ trunk/policycoreutils/audit2allow/sepolgen-ifgen 2007-02-05 19:01:07 UTC (rev 2220) @@ -0,0 +1,84 @@ +#! /usr/bin/python -E +# +# Authors: Karl MacMillan <kma...@me...> +# +# Copyright (C) 2006 Red Hat +# see file 'COPYING' for use and warranty information +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; version 2 only +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +# Parse interfaces and output extracted information about them +# suitable for policy generation. By default writes the output +# to the default location (obtained from sepolgen.defaults), but +# will output to another file provided as an argument: +# sepolgen-ifgen [headers] [output-filename] + + +import sys +import os + +import sepolgen.refparser as refparser +import sepolgen.defaults as defaults +import sepolgen.interfaces as interfaces + + +VERSION = "%prog .1" + +def parse_options(): + from optparse import OptionParser + + parser = OptionParser(version=VERSION) + parser.add_option("-o", "--output", dest="output", default=defaults.interface_info(), + help="filename to store output") + parser.add_option("-i", "--interfaces", dest="headers", default=defaults.headers(), + help="location of the interface header files") + parser.add_option("-v", "--verbose", action="store_true", default=False, + help="print debuging output") + options, args = parser.parse_args() + + return options + + +def main(): + options = parse_options() + + # Open the output first to generate errors before parsing + try: + f = open(options.output, "w") + except IOError, e: + sys.stderr.write("could not open output file [%s]\n" % options.output) + return 1 + + if options.verbose: + log = sys.stdout + else: + log = None + + try: + headers = refparser.parse_headers(options.headers, output=log) + except ValueError, e: + print "error parsing headers" + print str(e) + return 1 + + if_set = interfaces.InterfaceSet(output=log) + if_set.add_headers(headers) + if_set.to_file(f) + f.close() + + return 0 + +if __name__ == "__main__": + sys.exit(main()) Added: trunk/sepolgen/COPYING =================================================================== --- trunk/sepolgen/COPYING (rev 0) +++ trunk/sepolgen/COPYING 2007-02-05 19:01:07 UTC (rev 2220) @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + 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, write to the Free So... [truncated message content] |