diff --git a/refpolicy/Makefile b/refpolicy/Makefile index 631a2e3..2c7ba7e 100644 --- a/refpolicy/Makefile +++ b/refpolicy/Makefile @@ -50,7 +50,6 @@ LOADPOLICY := $(SBINDIR)/load_policy SETFILES := $(SBINDIR)/setfiles XMLLINT := $(BINDIR)/xmllint -XMLDTD := policy.dtd # enable MLS if requested. ifeq ($(MLS),y) @@ -108,6 +107,15 @@ ALL_FC_FILES := $(foreach dir,$(ALL_LAYERS),$(wildcard $(dir)/*.fc)) POLICY_SECTIONS := tmp/pre_te_files.conf tmp/generated_definitions.conf tmp/all_interfaces.conf tmp/all_attrs_types.conf tmp/only_te_rules.conf tmp/all_post.conf +DOCTOOLS = doctools +XMLDTD = $(DOCTOOLS)/policy.dtd +HTMLHEAD = $(DOCTOOLS)/header.html +HTMLFOOT = $(DOCTOOLS)/footer.html +HTMLCSS = $(DOCTOOLS)/style.css +HTMLOUT = $(DOCTOOLS)/html +JAVASRC = $(wildcard $(DOCTOOLS)/src/*.java) $(wildcard $(DOCTOOLS)/src/policy/*.java) +JAVABYTE = $(patsubst %.java,%.class,$(JAVASRC)) + ######################################## # # default action: build policy locally @@ -280,10 +288,9 @@ relabel: $(FC) $(SETFILES) # Documentation generation # -xml: policy.xml - -policy.xml: $(ALL_INTERFACES) tmp/generated_definitions.conf +tmp/policy.xml: $(ALL_INTERFACES) tmp/generated_definitions.conf @echo "Creating $@" + @cp $(XMLDTD) tmp $(QUIET) echo '' > $@ $(QUIET) echo '' >> $@ $(QUIET) echo "" >> $@ @@ -295,6 +302,15 @@ policy.xml: $(ALL_INTERFACES) tmp/generated_definitions.conf $(XMLLINT) --noout --dtdvalid $(XMLDTD) $@ ;\ fi +$(JAVABYTE) doctool: $(JAVASRC) + javac $(JAVASRC) + +html: tmp/policy.xml $(JAVABYTE) $(HTMLHEAD) $(HTMLFOOT) + @mkdir -p $(DOCTOOLS)/html + $(QUIET) java -cp $(DOCTOOLS)/src/ Docgen -xf tmp/policy.xml \ + -hf $(HTMLHEAD) -ff $(HTMLFOOT) -od $(HTMLOUT) + $(QUIET) cp $(HTMLCSS) $(HTMLOUT) + ######################################## # # Runtime binary policy patching of users @@ -369,5 +385,7 @@ clean: rm -f policy.conf rm -f policy.$(PV) rm -f $(FC) + rm -fR $(HTMLOUT) + find $(DOCTOOLS)/src -iname "*.class" | xargs rm -f -.PHONY: default policy install reload enableaudit checklabels restorelabels relabel xml clean +.PHONY: default policy install reload enableaudit checklabels restorelabels relabel html clean diff --git a/refpolicy/doc/doctools/footer.html b/refpolicy/doc/doctools/footer.html new file mode 100644 index 0000000..308b1d0 --- /dev/null +++ b/refpolicy/doc/doctools/footer.html @@ -0,0 +1,2 @@ + + diff --git a/refpolicy/doc/doctools/header.html b/refpolicy/doc/doctools/header.html new file mode 100644 index 0000000..daf0904 --- /dev/null +++ b/refpolicy/doc/doctools/header.html @@ -0,0 +1,8 @@ + + + +Security Enhanced Linux Reference Policy + + + + diff --git a/refpolicy/doc/doctools/policy.dtd b/refpolicy/doc/doctools/policy.dtd new file mode 100644 index 0000000..6d21a1b --- /dev/null +++ b/refpolicy/doc/doctools/policy.dtd @@ -0,0 +1,17 @@ + + + + + + + + + + + diff --git a/refpolicy/doc/doctools/src/Converter.java b/refpolicy/doc/doctools/src/Converter.java new file mode 100644 index 0000000..91378fd --- /dev/null +++ b/refpolicy/doc/doctools/src/Converter.java @@ -0,0 +1,247 @@ +/* Copyright (C) 2005 Tresys Technology, LLC + * License: refer to COPYING file for license information. + * Authors: Spencer Shimko + * + * Converter.java: The reference policy documentation converter + * Version: @version@ + */ +import policy.*; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.IOException; +import java.io.PrintStream; + +import java.util.Map; + +/** + * The reference policy documentation generator and xml analyzer class. + * It pulls in XML describing reference policy, transmogrifies it, + * and spits it back out in some other arbitrary format. + */ +public class Converter{ + private Policy policy; + private static final String HTMLEXT = ".html"; + private static final String indexContent = + "

Welcome to the reference policy API!

" + + "Please choose from the navigation options to the left.

"; + + private StringBuffer headerOutput = new StringBuffer(); + private StringBuffer footerOutput = new StringBuffer(); + private File outDir; + + public Converter(Policy pol, File headerFile, File footerFile) throws IOException{ + policy = pol; + + /* + * Setup header and footer. + */ + FileReader headIn = new FileReader(headerFile); + + BufferedReader br = new BufferedReader(headIn); + String line = null; //not declared within while loop + while (( line = br.readLine()) != null){ + headerOutput.append(line); + headerOutput.append(System.getProperty("line.separator")); + } + + FileReader footerIn = new FileReader(footerFile); + + br = new BufferedReader(footerIn); + line = null; //not declared within while loop + while (( line = br.readLine()) != null){ + footerOutput.append(line); + footerOutput.append(System.getProperty("line.separator")); + } + } + + public void Convert(File _outDir) throws IOException{ + outDir = _outDir; + + // write the index document + FileWrite("index" + HTMLEXT, headerOutput.toString() + + Menu().toString() + indexContent + footerOutput.toString()); + + // walk the policy and write pages for each module + for(Map.Entry lay:policy.Children.entrySet()){ + Layer layer = lay.getValue(); + // the base output contains the menu and layer content header + StringBuffer baseOutput = new StringBuffer(); + // the layer output will be filled with modules and summarys for content + StringBuffer layerOutput = new StringBuffer(); + + // create the navigation menu + baseOutput.append(Menu(layer.Name)); + + baseOutput.append("
\n"); + baseOutput.append("\t

Layer: " + layer.Name + "

\n"); + + layerOutput.append("\n"); + layerOutput.append("" + + ""); + + for(Map.Entry mod:layer.Children.entrySet()){ + // module output will be filled with in-depth module info. + StringBuffer moduleOutput = new StringBuffer(); + Module module = mod.getValue(); + + // get the content for the module's document + moduleOutput.append(moduleContent(mod.getValue()).toString() + ""); + + // get the summary and name for the layer's document + + layerOutput.append("" + + "\n\n"); + + // write module document + FileWrite(layer.Name + "_" + module.Name + HTMLEXT, + headerOutput.toString() + "\n" + baseOutput.toString() + moduleOutput.toString() + footerOutput.toString()); + } + // write layer document + FileWrite(layer.Name + HTMLEXT, + headerOutput.toString() + "\n" + baseOutput.toString() + + layerOutput.toString() + "" + footerOutput.toString()); + + } + } + + private StringBuffer Menu(String key){ + StringBuffer out = new StringBuffer(); + out.append("
\n"); + for(Map.Entry layer:policy.Children.entrySet()){ + String layerName = layer.getKey(); + + + // show the modules for the current key + if (layerName.equals(key)){ + out.append("\t" + layerName + "
\n"); + out.append("\t
\n"); + for(Map.Entry module:layer.getValue().Children.entrySet()){ + String moduleName = module.getKey(); + out.append("\t\t- " + moduleName + "
\n"); + } + out.append("\t
\n"); + } else { + out.append("\t+ " + layerName + "
\n"); + } + } + out.append("
"); + return out; + } + + private StringBuffer Menu(){ + StringBuffer out = new StringBuffer(); + out.append("
\n"); + for(Map.Entry layer:policy.Children.entrySet()){ + String layerName = layer.getKey(); + + + out.append("\t" + layerName + "
\n"); + out.append("\t
\n"); + for(Map.Entry module:layer.getValue().Children.entrySet()){ + String moduleName = module.getKey(); + out.append("\t\t- " + moduleName + "
\n"); + } + out.append("\t
\n"); + } + out.append("
"); + return out; + } + + private StringBuffer moduleContent(Module module){ + StringBuffer out = new StringBuffer(); + + out.append("\t

Module: "+ module.Name + "
\n"); + out.append("\tSummary: " + module.PCDATA + "

\n"); + for (Map.Entry inter:module.Children.entrySet()){ + Interface iface = inter.getValue(); + // main table header + out.append("
Module NameSummary
" + module.Name + "" + module.PCDATA + "
\n"); + out.append("\n"); + + // only show weight when type isnt none + if (iface.Type != InterfaceType.None){ + out.append("\n" + + "\n"); + out.append("\t\n"); + } else { + out.append("\n"); + out.append("\n"); + + } + out.append("\n"); + + out.append("
Interface
Name" + iface.Name + "
Flow Type" + iface.Type.toString() + "
Flow Weight" + iface.Weight + "
Name" + iface.Name + "
Flow Type" + iface.Type.toString() + "
Description" + iface.PCDATA + "
\n" + + "" + + ""); + for (Map.Entry param:iface.Children.entrySet()){ + Parameter parameter = param.getValue(); + out.append("\t\n"); + out.append("\t\n"); + String opt = parameter.GetAttribute("optional"); + if (opt != null && opt.equalsIgnoreCase("true")){ + out.append("\t\n"); + } else { + out.append("\t\n"); + } + } + out.append("\n
ParameterDescriptionOptional
" + parameter.Name + "" + parameter.PCDATA + "
Yes
No


\n"); + } + return out; + } + + /** + * Write to sub directory. + * @param path + * @param outFilename + * @param content + * @return + */ + private void FileWrite (String path, String outFilename, String content){ + try { + // create parent if necessary + File outParent = new File(outDir, path ); + File outFile = new File(outParent, outFilename ); + if (outParent.exists() && !outParent.isDirectory()){ + throw new IOException("Output directory not really a directory"); + } else if (!outParent.exists()){ + outParent.mkdirs(); + } + PrintStream stream = new PrintStream(new FileOutputStream(outFile)); + stream.println(content); + stream.flush(); + stream.close(); + } catch (Exception e){ + System.err.println (e.getMessage()); + System.exit(1); + } + } + + /** + * Write to output directory directly. + * + * @param path + * @param outFilename + * @param content + * @return + */ + private void FileWrite (String outFilename, String content){ + try { + File out = new File(outDir, outFilename ); + PrintStream stream = new PrintStream(new FileOutputStream(out)); + stream.println(content); + stream.flush(); + stream.close(); + } catch (Exception e){ + System.err.println (e.getMessage()); + System.exit(1); + } + } +} \ No newline at end of file diff --git a/refpolicy/doc/doctools/src/Docgen.java b/refpolicy/doc/doctools/src/Docgen.java new file mode 100644 index 0000000..12e38bf --- /dev/null +++ b/refpolicy/doc/doctools/src/Docgen.java @@ -0,0 +1,565 @@ +/* Copyright (C) 2005 Tresys Technology, LLC + * License: refer to COPYING file for license information. + * Authors: Spencer Shimko + * + * Docgen.java: The reference policy xml analyzer and documentation generator + */ +import policy.*; + +import java.io.*; +import java.util.*; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import javax.xml.validation.SchemaFactory; +import javax.xml.validation.Schema; + +import javax.xml.XMLConstants; + +import org.xml.sax.*; +import org.w3c.dom.*; + +/** + * The reference policy documentation generator and xml analyzer class. + * It pulls in XML describing reference policy, transmogrifies it, + * and spits it back out in some other arbitrary format. + */ +public class Docgen{ + // store the PIs here + private static Vector procInstr = new Vector(); + private static boolean verbose = false; + // the policy structure built after xml is parsed + private Policy policy = null; + // the xml document + private Document dom = null; + + // the files/directories passed in from the command line + private static File xmlFile; + private static File headerFile; + private static File footerFile; + private static File outputDir; + + private static void printUsage(){ + System.out.println("Reference Policy Documentation Compiler usage:"); + System.out.println("\tjava -cp ./src Docgen [-h] [-v] -xf xmlFileIn -hf headerFile -ff footerFile -od outDirectory"); + System.out.println("-h display this message and exit"); + System.out.println("-xf XML file to parse"); + System.out.println("-hf header file for HTML output"); + System.out.println("-ff footer file for HTML output"); + System.out.println("-od output directory"); + System.exit(1); + } + + /** + * Docgen constructor + * + * @param output Filename to setup for output + */ + public Docgen(String output) + throws FileNotFoundException { + } + + /** + * The main() driver for the policy documentation generator. + * @param argv Arguments, takes 1 filename parameter + */ + public static void main(String argv[]) { + if (argv.length == 0){ + printUsage(); + System.exit(1); + } + // hacked up version of getopt() + for (int x=0; x < argv.length; x++){ + if (argv[x].equals("-xf")){ + x++; + if (x + * + * Interface.java: The reference policy interfaces + * Version: @version@ + */ +package policy; + +import java.util.Map; +import java.util.TreeMap; + +/** + * Each reference policy interface is represented by this class. + * + * @see Layer + * @see Module + * @see Parameter + */ +public class Interface extends PolicyElement { + /** the children of this element */ + public final Map Children; + + public InterfaceType Type; + public int Weight; + + /** + * Default constructor assigns name to module. + * + * @param _name The name of the module. + * @param _Parent The reference to the parent element. + */ + public Interface(String _name, Module _Parent){ + super(_name, _Parent); + Children = new TreeMap(); + } +} \ No newline at end of file diff --git a/refpolicy/doc/doctools/src/policy/InterfaceType.java b/refpolicy/doc/doctools/src/policy/InterfaceType.java new file mode 100644 index 0000000..0a102c5 --- /dev/null +++ b/refpolicy/doc/doctools/src/policy/InterfaceType.java @@ -0,0 +1,12 @@ +/* Copyright (C) 2005 Tresys Technology, LLC + * License: refer to COPYING file for license information. + * Authors: Spencer Shimko + * + * Interface.java: The reference policy interface types + * Version: @version@ + */ +package policy; + +public enum InterfaceType { + Read, Write, Both, None; +} \ No newline at end of file diff --git a/refpolicy/doc/doctools/src/policy/Layer.java b/refpolicy/doc/doctools/src/policy/Layer.java new file mode 100644 index 0000000..b232a38 --- /dev/null +++ b/refpolicy/doc/doctools/src/policy/Layer.java @@ -0,0 +1,34 @@ +/* Copyright (C) 2005 Tresys Technology, LLC + * License: refer to COPYING file for license information. + * Authors: Spencer Shimko + * + * Layer.java: The reference policy layers + * Version: @version@ + */ +package policy; + +import java.util.Map; +import java.util.TreeMap; + +/** + * Each reference policy layer is represented by this class. + * + * @see Module + * @see Interface + * @see Parameter + */ +public class Layer extends PolicyElement { + /** the children of this element */ + public final Map Children; + + /** + * Default constructor assigns name to layer. + * + * @param _name The name of the layer. + * @param _Parent The reference to the parent element. + */ + public Layer(String _name, Policy _Parent){ + super(_name, _Parent); + Children = new TreeMap(); + } +} \ No newline at end of file diff --git a/refpolicy/doc/doctools/src/policy/Module.java b/refpolicy/doc/doctools/src/policy/Module.java new file mode 100644 index 0000000..3bb0c22 --- /dev/null +++ b/refpolicy/doc/doctools/src/policy/Module.java @@ -0,0 +1,34 @@ +/* Copyright (C) 2005 Tresys Technology, LLC + * License: refer to COPYING file for license information. + * Authors: Spencer Shimko + * + * Module.java: The reference policy module + * Version: @version@ + */ +package policy; + +import java.util.Map; +import java.util.TreeMap; + +/** + * Each reference policy layer is represented by this class. + * + * @see Layer + * @see Interface + * @see Parameter + */ +public class Module extends PolicyElement { + /** the children of this element */ + public final Map Children; + + /** + * Default constructor assigns name to module. + * + * @param _name The name of the module. + * @param _Parent The reference to the parent element. + */ + public Module(String _name, Layer _Parent){ + super(_name, _Parent); + Children = new TreeMap(); + } +} \ No newline at end of file diff --git a/refpolicy/doc/doctools/src/policy/Parameter.java b/refpolicy/doc/doctools/src/policy/Parameter.java new file mode 100644 index 0000000..0f0ee45 --- /dev/null +++ b/refpolicy/doc/doctools/src/policy/Parameter.java @@ -0,0 +1,28 @@ +/* Copyright (C) 2005 Tresys Technology, LLC + * License: refer to COPYING file for license information. + * Authors: Spencer Shimko + * + * Parameter.java: The reference policy interface parameters + * Version: @version@ + */ +package policy; + +/** + * Each reference policy layer is represented by this class. + * + * @see Layer + * @see Module + * @see Interface + */ +public class Parameter extends PolicyElement{ + + /** + * Default constructor assigns name to parameter. + * + * @param _name The name of the parameter. + * @param _Parent The reference to the parent element. + */ + public Parameter(String _name, Interface _Parent){ + super(_name, _Parent); + } +} \ No newline at end of file diff --git a/refpolicy/doc/doctools/src/policy/Policy.java b/refpolicy/doc/doctools/src/policy/Policy.java new file mode 100644 index 0000000..e17ff1f --- /dev/null +++ b/refpolicy/doc/doctools/src/policy/Policy.java @@ -0,0 +1,35 @@ +/* Copyright (C) 2005 Tresys Technology, LLC + * License: refer to COPYING file for license information. + * Authors: Spencer Shimko + * + * Policy.java: The reference policy api + * Version: @version@ + */ +package policy; + +import java.util.Map; +import java.util.TreeMap; + +/** + * Each reference policy layer is represented by this class. + * + * @see Module + * @see Interface + * @see Parameter + */ +public class Policy extends PolicyElement { + /** the children of this element */ + public final Map Children; + + /** + * Default constructor assigns name to layer. + * + * @param _name The name of the layer. + * @param _Parent The reference to the parent element. + */ + public Policy(String _name){ + // the policy is the root element so parent==null + super(_name, null); + Children = new TreeMap(); + } +} \ No newline at end of file diff --git a/refpolicy/doc/doctools/src/policy/PolicyElement.java b/refpolicy/doc/doctools/src/policy/PolicyElement.java new file mode 100644 index 0000000..f5fc913 --- /dev/null +++ b/refpolicy/doc/doctools/src/policy/PolicyElement.java @@ -0,0 +1,114 @@ +/* Copyright (C) 2005 Tresys Technology, LLC + * License: refer to COPYING file for license information. + * Authors: Spencer Shimko + * + * PolicyElement.java: The reference policy base class + * Version: @version@ + */ +package policy; + +import java.util.Map; +import java.util.TreeMap; + +/** + * Reference policy elements have certain similarties which + * should be inherited from a base class. This includes a name + * attribute that will be used for hashing, sorting, and converting + * to a string. + * + * @see Layer + * @see Module + * @see Interface + * @see Parameter + */ +public abstract class PolicyElement { + /** the string identifying the element */ + public final String Name; + /** the parent component */ + public final PolicyElement Parent; + + /** the attributes of this element */ + private final Map attributes; + + public String PCDATA; + + /** + * Default constructor assigns name. + * + * @param _name The name of the element. + * @param _Parent The reference to the parent element. + */ + public PolicyElement(String _name, PolicyElement _Parent){ + Name = _name; + Parent = _Parent; + attributes = new TreeMap(); + } + + /** + * Add attribute to policy element. + * + * @param aName String to identify attribute + * @param aString Value of attribute identified by string aName + * @return true when attribute added to element, + * false when attribute already defined for element + */ + public boolean AddAttribute(String aName, String aString){ + if (attributes.containsKey(aName)){ + return false; + } + attributes.put(aName,aString); + return true; + } + + /** + * Get attribute from policy element. + * + * @param aName String to identify attribute + * @return String value associated with named attribute + * or null if no attribute defined + * for aName. + */ + public String GetAttribute(String aName){ + return attributes.get(aName); + } + + /** + * Overridden equals method + * + * @param obj Object for comparison + */ + @Override public boolean equals(Object obj){ + return obj.toString().equals(this.Name); + } + + /** + * Return a hashcode for the element. Currently implemented as a + * call to the String hashCode() method. + * + * @return integer hashCode of this instance assuring two objects that + * are == will return same hashcode. + */ + @Override public int hashCode() { + return this.toString().hashCode(); + } + + /** + * Overridden toString() method. + * + * @return String representation of instance (it's name). + */ + @Override public String toString(){ + return Name; + } + + /** + * Since Component might be used as a key in some type of sort Compare + * is implemented. + * + * @return 0 if this==that, <0 if this0 if this>that + * @see String.compareTo + */ + public int compareTo(Layer that){ + return Name.compareTo(that.Name); + } +} \ No newline at end of file diff --git a/refpolicy/doc/doctools/style.css b/refpolicy/doc/doctools/style.css new file mode 100644 index 0000000..3805bf8 --- /dev/null +++ b/refpolicy/doc/doctools/style.css @@ -0,0 +1,152 @@ +body { + margin:0px; + padding:0px; + font-family:verdana, arial, helvetica, sans-serif; + color:#333; + background-color:white; + } +h1 { + margin:0px 0px 15px 0px; + padding:0px; + font-size:28px; + line-height:28px; + font-weight:900; + color:#ccc; + } +h2 { + font-size:100%; + } +h3 { + font-size:75%; + } +h4 { + font-size:67%; + } +li { + font:11px/20px verdana, arial, helvetica, sans-serif; + margin:0px 0px 0px 0px; + padding:0px; + } +p { + /* normal */ + font:11px/20px verdana, arial, helvetica, sans-serif; + margin:0px 0px 16px 0px; + padding:0px; + } + +tt { + /* inline code */ + font-family: monospace; + } + +table { + background-color:#eee; + border:1px dashed #999; + /*background-color: white;*/ + color: black; + text-align: left; + font:11px/20px verdana, arial, helvetica, sans-serif; + margin-left: 10%; + margin-right: 10%; +} + +th { + background-color: #ccccff; + text-align: center; +} + +td.header { + font-weight: bold; +} + +#Content>p {margin:0px;} +#Content>p+p {text-indent:30px;} +a { + color:#09c; + font-size:11px; + text-decoration:none; + font-weight:600; + font-family:verdana, arial, helvetica, sans-serif; + } +a:link {color:#09c;} +a:visited {color:#07a;} +a:hover {background-color:#eee;} + +#Codeblock { + margin:5px 50px 5px 50px; + padding:5px 0px 5px 15px; + border-style:solid; + border-color:black; + border-width:1px 1px 1px 1px; + background-color:#f8f8f8; + font-size:11px; + font-weight:600; + text-decoration:none; + font-family:courier; +} +pre { + font-size:11px; + font-weight:600; + text-decoration:none; + font-family:courier; +} +pre.codeblock { + /* code block (bordered, slight gray background) */ + border-style:solid; + border-color:black; + border-width:1px 1px 1px 1px; + background-color:#f8f8f8; + margin-left: 10%; + margin-right: 10%; +} +dl { + /* definition text block */ + font:11px/20px verdana, arial, helvetica, sans-serif; + margin:0px 0px 16px 0px; + padding:0px; + } +dt { + /* definition term */ + font-weight: bold; + } + +#Header { + margin:50px 0px 10px 0px; + padding:17px 0px 0px 20px; + /* For IE5/Win's benefit height = [correct height] + [top padding] + [top and bottom border widths] */ + height:33px; /* 14px + 17px + 2px = 33px */ + border-style:solid; + border-color:black; + border-width:1px 0px; /* top and bottom borders: 1px; left and right borders: 0px */ + line-height:11px; + font-size:110%; + background-color:#eee; + voice-family: "\"}\""; + voice-family:inherit; + height:14px; /* the correct height */ + } +body>#Header {height:14px;} +#Content { + margin:0px 50px 50px 200px; + padding:10px; + } + +#Menu { + position:absolute; + top:100px; + left:20px; + width:162px; + padding:10px; + background-color:#eee; + border:1px dashed #999; + line-height:17px; + text-align:left; + voice-family: "\"}\""; + voice-family:inherit; + width:160px; + } +#Menu subitem { + font-size: 5px; +} + +body>#Menu {width:160px;}