summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSumit Bose <sbose@nb.localdomain>2008-09-18 10:46:33 +0200
committerSumit Bose <sbose@nb.localdomain>2008-09-18 10:46:33 +0200
commit7bfb88bbf648000b4c2bf853a11ad2bd3f4b2d85 (patch)
treeb5e5bf2cd5768dd129d23fb76cb30304cd5315e5
parent575f23f9ca93b302cb487c037edcbb8bf7554437 (diff)
added fcusack's work
-rw-r--r--sudoers/ipa.rng42
-rw-r--r--sudoers/netgroup.rng49
-rw-r--r--sudoers/options.rng448
-rw-r--r--sudoers/posixGroup.rng49
-rw-r--r--sudoers/sudoOptions.rng73
-rw-r--r--sudoers/sudoers.rng64
-rw-r--r--sudoers/sudoers.xslt566
-rw-r--r--sudoers/sudoers2xml (renamed from sudoers2xml)0
-rw-r--r--sudoers/ttygroup.rng49
-rw-r--r--sudoers/user.rng49
-rw-r--r--sudoers/username.rng11
11 files changed, 1400 insertions, 0 deletions
diff --git a/sudoers/ipa.rng b/sudoers/ipa.rng
new file mode 100644
index 0000000..759caee
--- /dev/null
+++ b/sudoers/ipa.rng
@@ -0,0 +1,42 @@
+<grammar xmlns="http://relaxng.org/ns/structure/1.0"
+ xmlns:a="http://freeipa.org/xml/rng/ns/annotations/1.0">
+ <a:doc> top (root) level IPA pattern </a:doc>
+
+ <!-- this simply allows any valid XML to be enclosed in <ipa> -->
+ <start ns="http://freeipa.org/xml/rng/ipa/1.0">
+ <element name="ipa">
+ <!-- note that text is not allowed -->
+ <zeroOrMore>
+ <ref name="anyElement" />
+ </zeroOrMore>
+ </element>
+ </start>
+
+ <!--
+ This allows anything in ANOTHER namespace.
+ The way nsName works requires that this be in each schema (grammar);
+ it cannot be included.
+ -->
+ <define name="anyElement">
+ <element>
+ <anyName>
+ <except>
+ <nsName />
+ <nsName ns="" />
+ <nsName ns="http://freeipa.org/xml/rng/ipa/1.0" />
+ </except>
+ </anyName>
+ <zeroOrMore>
+ <choice>
+ <attribute>
+ <anyName />
+ </attribute>
+ <text/>
+ <ref name="anyElement" />
+ </choice>
+ </zeroOrMore>
+ </element>
+ </define>
+
+</grammar>
+
diff --git a/sudoers/netgroup.rng b/sudoers/netgroup.rng
new file mode 100644
index 0000000..24e0171
--- /dev/null
+++ b/sudoers/netgroup.rng
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<grammar xmlns="http://relaxng.org/ns/structure/1.0"
+ datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"
+ xmlns:a="http://freeipa.org/xml/rng/ns/annotations/1.0">
+
+ <a:doc> netgroup configuration</a:doc>
+
+ <start ns="http://freeipa.org/xml/rng/netgroup/1.0">
+ <element name="netgroup">
+ <ref name="options"/>
+ <ref name="anyElement"/>
+ </element>
+
+ </start>
+
+ <define name="options">
+ <zeroOrMore>
+ <choice>
+ <attribute name="groupnames">
+ <text/>
+ </attribute>
+ </choice>
+ </zeroOrMore>
+ </define>
+ <!--
+ This allows anything in another namespace.
+ The way nsName works requires that this be in each schema (grammar);
+ it cannot be included.
+ -->
+ <define name="anyElement">
+ <element>
+ <anyName>
+ <except>
+ <nsName/>
+ <nsName ns=""/>
+ </except>
+ </anyName>
+ <zeroOrMore>
+ <choice>
+ <attribute>
+ <anyName/>
+ </attribute>
+ <text/>
+ <ref name="anyElement"/>
+ </choice>
+ </zeroOrMore>
+ </element>
+ </define>
+</grammar>
diff --git a/sudoers/options.rng b/sudoers/options.rng
new file mode 100644
index 0000000..e2782e1
--- /dev/null
+++ b/sudoers/options.rng
@@ -0,0 +1,448 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<grammar xmlns="http://relaxng.org/ns/structure/1.0"
+ datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"
+ xmlns:a="http://freeipa.org/xml/rng/ns/annotations/1.0">
+
+ <include href="username.rng"/>
+
+ <define name="options">
+ <oneOrMore>
+ <choice>
+
+ <!-- flag options -->
+
+ <attribute name="always_set_home" a:defaultValue="off">
+ <choice>
+ <value>on</value>
+ <value>off</value>
+ </choice>
+ </attribute>
+
+ <attribute name="authenticate" a:defaultValue="on">
+ <choice>
+ <value>on</value>
+ <value>off</value>
+ </choice>
+ </attribute>
+
+ <attribute name="env_editor" a:defaultValue="on">
+ <choice>
+ <value>on</value>
+ <value>off</value>
+ </choice>
+ </attribute>
+
+ <attribute name="env_reset" a:defaultValue="off">
+ <choice>
+ <value>on</value>
+ <value>off</value>
+ </choice>
+ </attribute>
+
+ <attribute name="fqdn" a:defaultValue="off">
+ <choice>
+ <value>on</value>
+ <value>off</value>
+ </choice>
+ </attribute>
+
+<!--
+ this option is ignored by sudo
+ <attribute name="ignore_dot" a:defaultValue="on">
+ <choice>
+ <value>on</value>
+ <value>off</value>
+ </choice>
+ </attribute>
+-->
+
+<!-- global option only -->
+ <attribute name="ignore_local_sudoers" a:defaultValue="off">
+ <choice>
+ <value>on</value>
+ <value>off</value>
+ </choice>
+ </attribute>
+
+ <attribute name="insults" a:defaultValue="off">
+ <choice>
+ <value>on</value>
+ <value>off</value>
+ </choice>
+ </attribute>
+
+ <attribute name="log_host" a:defaultValue="off">
+ <choice>
+ <value>on</value>
+ <value>off</value>
+ </choice>
+ </attribute>
+
+ <attribute name="log_year" a:defaultValue="off">
+ <choice>
+ <value>on</value>
+ <value>off</value>
+ </choice>
+ </attribute>
+
+ <attribute name="long_otp_prompt" a:defaultValue="off">
+ <choice>
+ <value>on</value>
+ <value>off</value>
+ </choice>
+ </attribute>
+
+ <attribute name="mail_always" a:defaultValue="off">
+ <choice>
+ <value>on</value>
+ <value>off</value>
+ </choice>
+ </attribute>
+
+ <attribute name="mail_badpass" a:defaultValue="off">
+ <choice>
+ <value>on</value>
+ <value>off</value>
+ </choice>
+ </attribute>
+
+ <attribute name="mail_no_host" a:defaultValue="off">
+ <choice>
+ <value>on</value>
+ <value>off</value>
+ </choice>
+ </attribute>
+
+ <attribute name="mail_no_perms" a:defaultValue="off">
+ <choice>
+ <value>on</value>
+ <value>off</value>
+ </choice>
+ </attribute>
+
+ <attribute name="mail_no_user" a:defaultValue="on">
+ <choice>
+ <value>on</value>
+ <value>off</value>
+ </choice>
+ </attribute>
+
+ <attribute name="noexec" a:defaultValue="off">
+ <choice>
+ <value>on</value>
+ <value>off</value>
+ </choice>
+ </attribute>
+
+ <attribute name="path_info" a:defaultValue="off">
+ <choice>
+ <value>on</value>
+ <value>off</value>
+ </choice>
+ </attribute>
+
+ <attribute name="passprompt_override" a:defaultValue="off">
+ <choice>
+ <value>on</value>
+ <value>off</value>
+ </choice>
+ </attribute>
+
+ <attribute name="preserve_groups" a:defaultValue="off">
+ <choice>
+ <value>on</value>
+ <value>off</value>
+ </choice>
+ </attribute>
+
+ <attribute name="requiretty" a:defaultValue="off">
+ <choice>
+ <value>on</value>
+ <value>off</value>
+ </choice>
+ </attribute>
+
+ <attribute name="root_sudo" a:defaultValue="on">
+ <choice>
+ <value>on</value>
+ <value>off</value>
+ </choice>
+ </attribute>
+
+ <attribute name="rootpw" a:defaultValue="off">
+ <choice>
+ <value>on</value>
+ <value>off</value>
+ </choice>
+ </attribute>
+
+ <attribute name="runaspw" a:defaultValue="off">
+ <choice>
+ <value>on</value>
+ <value>off</value>
+ </choice>
+ </attribute>
+
+ <attribute name="set_home" a:defaultValue="off">
+ <choice>
+ <value>on</value>
+ <value>off</value>
+ </choice>
+ </attribute>
+
+ <attribute name="set_logname" a:defaultValue="on">
+ <choice>
+ <value>on</value>
+ <value>off</value>
+ </choice>
+ </attribute>
+
+ <attribute name="setenv" a:defaultValue="off">
+ <choice>
+ <value>on</value>
+ <value>off</value>
+ </choice>
+ </attribute>
+
+ <attribute name="shell_noargs" a:defaultValue="off">
+ <choice>
+ <value>on</value>
+ <value>off</value>
+ </choice>
+ </attribute>
+
+ <attribute name="stay_setuid" a:defaultValue="off">
+ <choice>
+ <value>on</value>
+ <value>off</value>
+ </choice>
+ </attribute>
+
+ <attribute name="targetpw" a:defaultValue="off">
+ <choice>
+ <value>on</value>
+ <value>off</value>
+ </choice>
+ </attribute>
+
+ <attribute name="tty_tickets" a:defaultValue="off">
+ <choice>
+ <value>on</value>
+ <value>off</value>
+ </choice>
+ </attribute>
+
+ <!-- integer options -->
+
+ <attribute name="passwd_tries" a:defaultValue="3">
+ <data type="integer">
+ <param name="minInclusive"> 1 </param>
+ <param name="maxInclusive"> 65535 </param> <!-- ??? -->
+ </data>
+ </attribute>
+
+ <!-- integer/boolean options -->
+
+ <attribute name="loglinelen" a:defaultValue="80">
+ <data type="integer">
+ <param name="minInclusive"> 0 </param>
+ <param name="maxInclusive"> 65535 </param> <!-- ??? -->
+ </data>
+ </attribute>
+
+ <attribute name="passwd_timeout" a:defaultValue="0">
+ <data type="integer">
+ <param name="minInclusive"> 0 </param>
+ <param name="maxInclusive"> 65535 </param> <!-- ??? -->
+ </data>
+ </attribute>
+
+ <attribute name="timestamp_timeout" a:defaultValue="5">
+ <data type="integer">
+ <param name="minInclusive"> -1 </param>
+ <param name="maxInclusive"> 65535 </param> <!-- ??? -->
+ </data>
+ </attribute>
+
+ <attribute name="umask" a:defaultValue="0022">
+ <data type="string">
+ <param name="pattern">(0[0-7]{3})</param>
+ </data>
+ </attribute>
+
+ <!-- string options -->
+ <attribute name="badpass_message" a:defaultValue="Sorry, try again.">
+ <text/>
+ </attribute>
+
+ <attribute name="editor" a:defaultValue="/PATH/TO/VI">
+ <!-- NOTE: absolute path not required -->
+ <text/>
+ </attribute>
+
+ <attribute name="mailsub"
+ a:defaultValue="*** SECURITY information for %h ***">
+ <text/>
+ </attribute>
+
+ <attribute name="noexec_file" a:defaultValue="/PATH/TO/SUDO_NOEXEC.SO">
+ <data type="string">
+ <param name="pattern">/.*</param>
+ </data>
+ </attribute>
+
+ <attribute name="passprompt" a:defaultValue="Password:">
+ <text/>
+ </attribute>
+
+ <attribute name="role" a:defaultValue="">
+ <text/>
+ </attribute>
+
+ <attribute name="runas_default" a:defaultValue="root">
+ <ref name="username_pattern"/>
+ </attribute>
+
+ <attribute name="syslog_badpri" a:defaultValue="alert">
+ <choice>
+ <value>emerg</value>
+ <value>alert</value>
+ <value>crit</value>
+ <value>err</value>
+ <value>warning</value>
+ <value>notice</value>
+ <value>info</value>
+ <value>debug</value>
+ </choice>
+ </attribute>
+
+ <attribute name="syslog_goodpri" a:defaultValue="notice">
+ <choice>
+ <value>emerg</value>
+ <value>alert</value>
+ <value>crit</value>
+ <value>err</value>
+ <value>warning</value>
+ <value>notice</value>
+ <value>info</value>
+ <value>debug</value>
+ </choice>
+ </attribute>
+
+ <attribute name="timestampdir" a:defaultValue="/var/db/sudo">
+ <data type="string">
+ <param name="pattern">/.*</param>
+ </data>
+ </attribute>
+
+ <attribute name="timestampowner" a:defaultValue="root">
+ <ref name="username_pattern"/>
+ </attribute>
+
+ <attribute name="type" a:defaultValue="">
+ <text/>
+ </attribute>
+
+ <!-- string/boolean options -->
+
+<!-- possibly bad option for us -->
+ <attribute name="exempt_group" a:defaultValue="off">
+ <text/>
+ </attribute>
+
+ <attribute name="lecture" a:defaultValue="once">
+ <choice>
+ <value>always</value>
+ <value>never</value>
+ <value>once</value>
+ </choice>
+ </attribute>
+
+ <attribute name="lecture_file" a:defaultValue="built-in">
+ <data type="string">
+ <param name="pattern">(/.*|built-in)</param>
+ </data>
+ </attribute>
+
+<!-- possibly bad for us -->
+ <attribute name="listpw" a:defaultValue="any">
+ <choice>
+ <value>all</value>
+ <value>always</value>
+ <value>any</value>
+ <value>never</value>
+ </choice>
+ </attribute>
+
+ <attribute name="logfile" a:defaultValue="off">
+ <data type="string">
+ <param name="pattern">(/.*|off)</param>
+ </data>
+ </attribute>
+
+ <attribute name="mailerflags" a:defaultValue="-t">
+ <text/>
+ </attribute>
+
+ <attribute name="mailerpath" a:defaultValue="/PATH/TO/SENDMAIL">
+ <text/>
+ </attribute>
+
+ <attribute name="syslog" a:defaultValue="authpriv">
+ <choice>
+ <value>auth</value>
+ <value>authpriv</value>
+ <value>daemon</value>
+ <value>user</value>
+ <value>local0</value>
+ <value>local1</value>
+ <value>local2</value>
+ <value>local3</value>
+ <value>local4</value>
+ <value>local5</value>
+ <value>local6</value>
+ <value>local7</value>
+ <value>off</value>
+ </choice>
+ </attribute>
+
+ <attribute name="verifypw" a:defaultValue="all">
+ <choice>
+ <value>all</value>
+ <value>always</value>
+ <value>any</value>
+ <value>never</value>
+ </choice>
+ </attribute>
+
+ <!-- list/boolean options -->
+
+ <attribute name="env_check" a:defaultValue="">
+ <list>
+ <oneOrMore>
+ <data type="string"/>
+ </oneOrMore>
+ </list>
+ </attribute>
+
+ <attribute name="env_delete" a:defaultValue="">
+ <list>
+ <oneOrMore>
+ <data type="string"/>
+ </oneOrMore>
+ </list>
+ </attribute>
+
+ <attribute name="env_keep" a:defaultValue="">
+ <list>
+ <oneOrMore>
+ <data type="string"/>
+ </oneOrMore>
+ </list>
+ </attribute>
+
+ </choice>
+ </oneOrMore>
+ </define> <!-- options -->
+</grammar>
+
diff --git a/sudoers/posixGroup.rng b/sudoers/posixGroup.rng
new file mode 100644
index 0000000..e3f4d86
--- /dev/null
+++ b/sudoers/posixGroup.rng
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<grammar xmlns="http://relaxng.org/ns/structure/1.0"
+ datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"
+ xmlns:a="http://freeipa.org/xml/rng/ns/annotations/1.0">
+
+ <a:doc> posixGroup configuration</a:doc>
+
+ <start ns="http://freeipa.org/xml/rng/posixGroup/1.0">
+ <element name="posixGroup">
+ <ref name="options"/>
+ <ref name="anyElement"/>
+ </element>
+
+ </start>
+
+ <define name="options">
+ <zeroOrMore>
+ <choice>
+ <attribute name="gids">
+ <text/>
+ </attribute>
+ </choice>
+ </zeroOrMore>
+ </define>
+ <!--
+ This allows anything in another namespace.
+ The way nsName works requires that this be in each schema (grammar);
+ it cannot be included.
+ -->
+ <define name="anyElement">
+ <element>
+ <anyName>
+ <except>
+ <nsName/>
+ <nsName ns=""/>
+ </except>
+ </anyName>
+ <zeroOrMore>
+ <choice>
+ <attribute>
+ <anyName/>
+ </attribute>
+ <text/>
+ <ref name="anyElement"/>
+ </choice>
+ </zeroOrMore>
+ </element>
+ </define>
+</grammar>
diff --git a/sudoers/sudoOptions.rng b/sudoers/sudoOptions.rng
new file mode 100644
index 0000000..c87c02b
--- /dev/null
+++ b/sudoers/sudoOptions.rng
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<grammar xmlns="http://relaxng.org/ns/structure/1.0"
+ datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"
+ xmlns:a="http://freeipa.org/xml/rng/ns/annotations/1.0">
+
+ <a:doc> Sudo options configuration (Defaults) </a:doc>
+
+ <include href="options.rng"/>
+
+ <start ns="http://freeipa.org/xml/rng/sudo/sudoOptions/1.0">
+ <element name="sudoOptions">
+ <ref name="options"/>
+ <!-- we can enclose anything -->
+ <!--
+ NOTE: This allows only a single element to be enclosed.
+ The problem with allowing multiple elements is, how to
+ resolve conflicting configs?
+
+ <sudoOptions ...>
+ <posixGroup name="wheel">
+ <sudoers .../>
+ </posixGroup>
+ <posixGroup name="staff">
+ <sudoers .../>
+ </posixGroup>
+ <posixUser name="user">
+ <sudoers .../>
+ </posixGroup>
+ </sudoOptions>
+
+ If user foo is in both groups, and (e.g.) conflicting
+ options are used in the <sudoers> element, which applies?
+ For the <posixUser> case, we could simply say it is more
+ specific and it wins, but not so easy for the groups case.
+
+ NOTE: This is a general problem. Even if sudoOptions allows only
+ a single element, what about other grouping elements?
+ -->
+ <ref name="anyElement"/>
+ </element>
+ </start>
+
+ <!--
+ This allows anything in another namespace.
+ The way nsName works requires that this be in each schema (grammar);
+ it cannot be included.
+ -->
+ <define name="anyElement">
+ <zeroOrMore>
+ <element>
+ <anyName>
+ <except>
+ <nsName/>
+ <nsName ns=""/>
+<!--
+ <nsName ns="http://freeipa.org/xml/rng/sudo/sudoOptions/1.0"/>
+-->
+ </except>
+ </anyName>
+ <zeroOrMore>
+ <choice>
+ <attribute>
+ <anyName/>
+ </attribute>
+ <text/>
+ <ref name="anyElement"/>
+ </choice>
+ </zeroOrMore>
+ </element>
+ </zeroOrMore>
+ </define>
+</grammar>
+
diff --git a/sudoers/sudoers.rng b/sudoers/sudoers.rng
new file mode 100644
index 0000000..6787df7
--- /dev/null
+++ b/sudoers/sudoers.rng
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<grammar xmlns="http://relaxng.org/ns/structure/1.0"
+ datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"
+ xmlns:a="http://freeipa.org/xml/rng/ns/annotations/1.0">
+
+ <a:doc> Sudo configuration (/etc/sudoers) </a:doc>
+
+ <include href="username.rng"/>
+
+ <start ns="http://freeipa.org/xml/rng/sudo/sudoers/1.0">
+ <element name="sudoers">
+
+ <oneOrMore>
+ <element name="command">
+ <optional>
+ <element name="options">
+ <ref name="options"/>
+ </element>
+ </optional>
+
+ <element name="path">
+ <text/>
+ </element>
+
+ <zeroOrMore>
+ <element name="args">
+ <text/>
+ </element>
+ </zeroOrMore>
+
+ <zeroOrMore>
+ <element name="tag">
+ <choice>
+ <value>NOPASSWD</value>
+ <value>PASSWD</value>
+ <value>NOEXEC</value>
+ <value>EXEC</value>
+ <value>SETENV</value>
+ <value>NOSETENV</value>
+ </choice>
+ </element>
+ </zeroOrMore>
+
+<!-- XXX actually needs to be user,group,netgroup -->
+ <zeroOrMore>
+ <element name="runas">
+ <ref name="username_pattern"/>
+ </element>
+ </zeroOrMore>
+
+ </element> <!-- command -->
+ </oneOrMore>
+
+ </element> <!-- sudoers -->
+ </start>
+ <define name="options">
+ <zeroOrMore>
+ <choice>
+ <attribute name="dummy_attribute"/>
+ </choice>
+ </zeroOrMore>
+ </define>
+</grammar>
+
diff --git a/sudoers/sudoers.xslt b/sudoers/sudoers.xslt
new file mode 100644
index 0000000..4b19e51
--- /dev/null
+++ b/sudoers/sudoers.xslt
@@ -0,0 +1,566 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet version="1.0"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ xmlns:md="http://freeipa.org/xsl/metadata/1.0"
+ xmlns:ipa10="http://freeipa.org/xml/rng/ipa/1.0"
+ xmlns:user10="http://freeipa.org/xml/rng/user/1.0"
+ xmlns:group10="http://freeipa.org/xml/rng/posixGroup/1.0"
+ xmlns:netgroup10="http://freeipa.org/xml/rng/netgroup/1.0"
+ xmlns:sudoOptions10="http://freeipa.org/xml/rng/sudo/sudoOptions/1.0"
+ xmlns:sudoers10="http://freeipa.org/xml/rng/sudo/sudoers/1.0">
+
+ <md:output_file name="/etc/sudoers" owner="root" group="root" permission="440"/>
+ <xsl:output method="text" indent="no"/>
+ <xsl:strip-space elements="*"/>
+
+ <xsl:template match="/">
+ <xsl:text># IPA generated /etc/sudoers: DO NOT EDIT&#xA;&#xA;</xsl:text>
+ <xsl:apply-templates select="ipa10:ipa"/>
+ </xsl:template>
+
+ <xsl:template match="ipa10:ipa">
+ <xsl:apply-templates>
+ <xsl:with-param name="users" select="''"/>
+ </xsl:apply-templates>
+ </xsl:template>
+
+ <xsl:template match="user10:user">
+ <xsl:param name="users"/>
+ <xsl:variable name="uids">
+ <xsl:call-template name="tokenize">
+ <xsl:with-param name="s" select="@uids"/>
+ </xsl:call-template>
+ </xsl:variable>
+
+ <xsl:variable name="space">
+ <xsl:choose>
+ <xsl:when test="$users = ''">
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:text> </xsl:text>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+
+ <xsl:apply-templates>
+ <xsl:with-param name="users" select="concat($users, $space, $uids)"/>
+ </xsl:apply-templates>
+
+ </xsl:template>
+
+ <xsl:template match="group10:posixGroup">
+ <xsl:param name="users"/>
+ <xsl:variable name="gids">
+ <xsl:call-template name="tokenize">
+ <xsl:with-param name="s" select="@gids"/>
+ <xsl:with-param name="prefix" select="'%'"/>
+ </xsl:call-template>
+ </xsl:variable>
+
+ <xsl:variable name="space">
+ <xsl:choose>
+ <xsl:when test="$users = ''">
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:text> </xsl:text>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+
+ <xsl:apply-templates>
+ <xsl:with-param name="users" select="concat($users, $space, $gids)"/>
+ </xsl:apply-templates>
+ </xsl:template>
+
+ <xsl:template match="netgroup10:netgroup">
+ <xsl:param name="users"/>
+ <xsl:variable name="netgroups">
+ <xsl:call-template name="tokenize">
+ <!--<xsl:with-param name="s" select="@netgroup"/> -->
+ <xsl:with-param name="s" select="@groupnames"/>
+ <xsl:with-param name="prefix" select="'+'"/>
+ </xsl:call-template>
+ </xsl:variable>
+
+ <xsl:variable name="space">
+ <xsl:choose>
+ <xsl:when test="$users = ''">
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:text> </xsl:text>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+
+ <xsl:apply-templates>
+ <xsl:with-param name="users" select="concat($users, $space, $netgroups)"/>
+ </xsl:apply-templates>
+ </xsl:template>
+
+ <xsl:template match="sudoOptions10:sudoOptions">
+ <xsl:param name="users"/>
+
+ <xsl:call-template name="defaults">
+ <xsl:with-param name="users" select="$users"/>
+ </xsl:call-template>
+ <xsl:apply-templates>
+ <xsl:with-param name="users" select="$users"/>
+ </xsl:apply-templates>
+ </xsl:template>
+
+ <xsl:template match="sudoers10:sudoers">
+ <xsl:param name="users"/>
+ <!-- Add this if <sudoers> is allowed to carry option (Defaults) attributes
+ <xsl:call-template name="defaults"/>
+ -->
+ <xsl:apply-templates select="sudoers10:command">
+ <xsl:with-param name="users" select="$users"/>
+ </xsl:apply-templates>
+ </xsl:template>
+
+ <xsl:template match="sudoers10:command">
+ <xsl:param name="users"/>
+
+ <xsl:variable name="runas">
+ <xsl:choose>
+ <xsl:when test="sudoers10:runas">
+ <xsl:for-each select="sudoers10:runas">
+ <xsl:if test="position() > 1">
+ <xsl:text>,</xsl:text>
+ </xsl:if>
+ <xsl:value-of select="."/>
+ </xsl:for-each>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="'ALL'"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+
+ <xsl:variable name="tags">
+ <xsl:choose>
+ <xsl:when test="sudoers10:tag">
+ <xsl:call-template name="tokenize">
+ <xsl:with-param name="s" select="sudoers10:tag"/>
+ <xsl:with-param name="suffix" select="':'"/>
+ </xsl:call-template>
+ <!-- Include a trailing space for easier output formatting. -->
+ <xsl:text> </xsl:text>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="''"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+
+ <xsl:variable name="command" select="sudoers10:path"/>
+ <xsl:variable name="args" select="sudoers10:args"/>
+
+ <!--
+ user|%group|+netgroup.USER HOST|+netgroup.HOST = (runas) tags: commands
+ runas::= user|#uid|%group|+netgroup.USER
+ -->
+ <xsl:call-template name="tokenize">
+ <xsl:with-param name="s" select="$users"/>
+ <xsl:with-param name="suffix">
+ <xsl:text> </xsl:text>
+ <xsl:text>ALL</xsl:text>
+ <xsl:text> = (</xsl:text>
+ <xsl:value-of select="$runas"/>
+ <xsl:text>) </xsl:text>
+ <xsl:value-of select="$tags"/>
+ <xsl:value-of select="$command"/>
+ <xsl:text> </xsl:text>
+ <xsl:value-of select="$args"/>
+ </xsl:with-param>
+ <xsl:with-param name="separator" select="'&#xA;'"/>
+ </xsl:call-template>
+
+ <xsl:text>&#xA;</xsl:text>
+ </xsl:template>
+
+ <xsl:template name="defaults">
+ <xsl:param name="users"/>
+
+ <xsl:for-each select="@*">
+ <xsl:variable name="var" select="name()"/>
+ <xsl:variable name="val" select="."/>
+ <xsl:variable name="prefix">
+ <xsl:choose>
+ <xsl:when test="$users = ''">
+ <xsl:text>Defaults</xsl:text>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:text>Defaults:</xsl:text>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+
+ <xsl:call-template name="tokenize">
+ <xsl:with-param name="s" select="$users"/>
+ <xsl:with-param name="prefix">
+ <xsl:choose>
+ <xsl:when test="$users = ''">
+ <xsl:text>Defaults</xsl:text>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:text>Defaults:</xsl:text>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:with-param>
+ <xsl:with-param name="suffix">
+ <xsl:text> </xsl:text>
+
+ <xsl:choose>
+ <!-- boolean handling -->
+
+ <xsl:when test="name() = 'always_set_home'">
+ <xsl:if test=". = 'off'">
+ <xsl:text>!</xsl:text>
+ </xsl:if>
+ <xsl:value-of select="name()"/>
+ </xsl:when>
+
+ <xsl:when test="name() = 'authenticate'">
+ <xsl:if test=". = 'off'">
+ <xsl:text>!</xsl:text>
+ </xsl:if>
+ <xsl:value-of select="name()"/>
+ </xsl:when>
+
+ <xsl:when test="name() = 'env_editor'">
+ <xsl:if test=". = 'off'">
+ <xsl:text>!</xsl:text>
+ </xsl:if>
+ <xsl:value-of select="name()"/>
+ </xsl:when>
+
+ <xsl:when test="name() = 'env_reset'">
+ <xsl:if test=". = 'off'">
+ <xsl:text>!</xsl:text>
+ </xsl:if>
+ <xsl:value-of select="name()"/>
+ </xsl:when>
+
+ <xsl:when test="name() = 'fqdn'">
+ <xsl:if test=". = 'off'">
+ <xsl:text>!</xsl:text>
+ </xsl:if>
+ <xsl:value-of select="name()"/>
+ </xsl:when>
+
+ <xsl:when test="name() = 'ignore_local_sudoers'">
+ <xsl:if test=". = 'off'">
+ <xsl:text>!</xsl:text>
+ </xsl:if>
+ <xsl:value-of select="name()"/>
+ </xsl:when>
+
+ <xsl:when test="name() = 'insults'">
+ <xsl:if test=". = 'off'">
+ <xsl:text>!</xsl:text>
+ </xsl:if>
+ <xsl:value-of select="name()"/>
+ </xsl:when>
+
+ <xsl:when test="name() = 'log_host'">
+ <xsl:if test=". = 'off'">
+ <xsl:text>!</xsl:text>
+ </xsl:if>
+ <xsl:value-of select="name()"/>
+ </xsl:when>
+
+ <xsl:when test="name() = 'log_year'">
+ <xsl:if test=". = 'off'">
+ <xsl:text>!</xsl:text>
+ </xsl:if>
+ <xsl:value-of select="name()"/>
+ </xsl:when>
+
+ <xsl:when test="name() = 'long_otp_prompt'">
+ <xsl:if test=". = 'off'">
+ <xsl:text>!</xsl:text>
+ </xsl:if>
+ <xsl:value-of select="name()"/>
+ </xsl:when>
+
+ <xsl:when test="name() = 'mail_always'">
+ <xsl:if test=". = 'off'">
+ <xsl:text>!</xsl:text>
+ </xsl:if>
+ <xsl:value-of select="name()"/>
+ </xsl:when>
+
+ <xsl:when test="name() = 'mail_badpass'">
+ <xsl:if test=". = 'off'">
+ <xsl:text>!</xsl:text>
+ </xsl:if>
+ <xsl:value-of select="name()"/>
+ </xsl:when>
+
+ <xsl:when test="name() = 'mail_no_host'">
+ <xsl:if test=". = 'off'">
+ <xsl:text>!</xsl:text>
+ </xsl:if>
+ <xsl:value-of select="name()"/>
+ </xsl:when>
+
+ <xsl:when test="name() = 'mail_no_perms'">
+ <xsl:if test=". = 'off'">
+ <xsl:text>!</xsl:text>
+ </xsl:if>
+ <xsl:value-of select="name()"/>
+ </xsl:when>
+
+ <xsl:when test="name() = 'mail_no_user'">
+ <xsl:if test=". = 'off'">
+ <xsl:text>!</xsl:text>
+ </xsl:if>
+ <xsl:value-of select="name()"/>
+ </xsl:when>
+
+ <xsl:when test="name() = 'noexec'">
+ <xsl:if test=". = 'off'">
+ <xsl:text>!</xsl:text>
+ </xsl:if>
+ <xsl:value-of select="name()"/>
+ </xsl:when>
+
+ <xsl:when test="name() = 'path_info'">
+ <xsl:if test=". = 'off'">
+ <xsl:text>!</xsl:text>
+ </xsl:if>
+ <xsl:value-of select="name()"/>
+ </xsl:when>
+
+ <xsl:when test="name() = 'passprompt_override'">
+ <xsl:if test=". = 'off'">
+ <xsl:text>!</xsl:text>
+ </xsl:if>
+ <xsl:value-of select="name()"/>
+ </xsl:when>
+
+ <xsl:when test="name() = 'preserve_groups'">
+ <xsl:if test=". = 'off'">
+ <xsl:text>!</xsl:text>
+ </xsl:if>
+ <xsl:value-of select="name()"/>
+ </xsl:when>
+
+ <xsl:when test="name() = 'requiretty'">
+ <xsl:if test=". = 'off'">
+ <xsl:text>!</xsl:text>
+ </xsl:if>
+ <xsl:value-of select="name()"/>
+ </xsl:when>
+
+ <xsl:when test="name() = 'root_sudo'">
+ <xsl:if test=". = 'off'">
+ <xsl:text>!</xsl:text>
+ </xsl:if>
+ <xsl:value-of select="name()"/>
+ </xsl:when>
+
+ <xsl:when test="name() = 'rootpw'">
+ <xsl:if test=". = 'off'">
+ <xsl:text>!</xsl:text>
+ </xsl:if>
+ <xsl:value-of select="name()"/>
+ </xsl:when>
+
+ <xsl:when test="name() = 'runaspw'">
+ <xsl:if test=". = 'off'">
+ <xsl:text>!</xsl:text>
+ </xsl:if>
+ <xsl:value-of select="name()"/>
+ </xsl:when>
+
+ <xsl:when test="name() = 'set_home'">
+ <xsl:if test=". = 'off'">
+ <xsl:text>!</xsl:text>
+ </xsl:if>
+ <xsl:value-of select="name()"/>
+ </xsl:when>
+
+ <xsl:when test="name() = 'set_logname'">
+ <xsl:if test=". = 'off'">
+ <xsl:text>!</xsl:text>
+ </xsl:if>
+ <xsl:value-of select="name()"/>
+ </xsl:when>
+
+ <xsl:when test="name() = 'setenv'">
+ <xsl:if test=". = 'off'">
+ <xsl:text>!</xsl:text>
+ </xsl:if>
+ <xsl:value-of select="name()"/>
+ </xsl:when>
+
+ <xsl:when test="name() = 'shell_noargs'">
+ <xsl:if test=". = 'off'">
+ <xsl:text>!</xsl:text>
+ </xsl:if>
+ <xsl:value-of select="name()"/>
+ </xsl:when>
+
+ <xsl:when test="name() = 'stay_setuid'">
+ <xsl:if test=". = 'off'">
+ <xsl:text>!</xsl:text>
+ </xsl:if>
+ <xsl:value-of select="name()"/>
+ </xsl:when>
+
+ <xsl:when test="name() = 'targetpw'">
+ <xsl:if test=". = 'off'">
+ <xsl:text>!</xsl:text>
+ </xsl:if>
+ <xsl:value-of select="name()"/>
+ </xsl:when>
+
+ <xsl:when test="name() = 'ttytickets'">
+ <xsl:if test=". = 'off'">
+ <xsl:text>!</xsl:text>
+ </xsl:if>
+ <xsl:value-of select="name()"/>
+ </xsl:when>
+
+ <!-- boolean/string handling -->
+
+ <xsl:when test="name() = 'syslog'">
+ <xsl:choose>
+ <xsl:when test=". = 'off'">
+ <xsl:text>!</xsl:text>
+ <xsl:value-of select="name()"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="name()"/>
+ <xsl:text>=</xsl:text>
+ <xsl:value-of select="."/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:when>
+
+ <!-- quoted/list handling -->
+
+ <xsl:when test="name() = 'badpass_message'">
+ <xsl:value-of select="$var"/>
+ <xsl:text>= "</xsl:text>
+ <xsl:value-of select="$val"/>
+ <xsl:text>"</xsl:text>
+ </xsl:when>
+
+ <xsl:when test="name() = 'mailsub'">
+ <xsl:value-of select="$var"/>
+ <xsl:text>= "</xsl:text>
+ <xsl:value-of select="$val"/>
+ <xsl:text>"</xsl:text>
+ </xsl:when>
+
+ <xsl:when test="name() = 'passprompt'">
+ <xsl:value-of select="$var"/>
+ <xsl:text>= "</xsl:text>
+ <xsl:value-of select="$val"/>
+ <xsl:text>"</xsl:text>
+ </xsl:when>
+
+ <xsl:when test="name() = 'role'">
+ <xsl:value-of select="$var"/>
+ <xsl:text>= "</xsl:text>
+ <xsl:value-of select="$val"/>
+ <xsl:text>"</xsl:text>
+ </xsl:when>
+
+ <xsl:when test="name() = 'mailerflags'">
+ <xsl:value-of select="$var"/>
+ <xsl:text>= "</xsl:text>
+ <xsl:value-of select="$val"/>
+ <xsl:text>"</xsl:text>
+ </xsl:when>
+
+ <xsl:when test="name() = 'env_check'">
+ <xsl:value-of select="$var"/>
+ <xsl:text>= "</xsl:text>
+ <xsl:value-of select="$val"/>
+ <xsl:text>"</xsl:text>
+ </xsl:when>
+
+ <xsl:when test="name() = 'env_delete'">
+ <xsl:value-of select="$var"/>
+ <xsl:text>= "</xsl:text>
+ <xsl:value-of select="$val"/>
+ <xsl:text>"</xsl:text>
+ </xsl:when>
+
+ <xsl:when test="name() = 'env_keep'">
+ <xsl:value-of select="$var"/>
+ <xsl:text>= "</xsl:text>
+ <xsl:value-of select="$val"/>
+ <xsl:text>"</xsl:text>
+ </xsl:when>
+
+ <!-- default handling -->
+ <xsl:otherwise>
+ <xsl:value-of select="name()"/>
+ <xsl:text>=</xsl:text>
+ <xsl:value-of select="."/>
+ </xsl:otherwise>
+
+ </xsl:choose>
+
+ <xsl:text>&#xA;</xsl:text>
+ </xsl:with-param>
+ <xsl:with-param name="separator" select="''"/>
+ </xsl:call-template>
+
+ <xsl:text>&#xA;</xsl:text>
+ </xsl:for-each>
+ </xsl:template>
+
+ <xsl:template name="tokenize">
+ <xsl:param name="s" select="."/>
+ <xsl:param name="delim" select="' '"/>
+ <xsl:param name="prefix" select="''"/>
+ <xsl:param name="suffix" select="''"/>
+ <xsl:param name="separator" select="' '"/>
+ <xsl:param name="action" select="'output'"/>
+ <xsl:param name="first" select="true()"/>
+
+ <xsl:choose>
+ <xsl:when test="contains($s, $delim)">
+ <xsl:choose>
+ <xsl:when test="$action = 'output'">
+ <xsl:if test="$first != true()">
+ <xsl:value-of select="$separator"/>
+ </xsl:if>
+ <xsl:value-of select="$prefix"/>
+ <xsl:value-of select="substring-before($s, $delim)"/>
+ <xsl:value-of select="$suffix"/>
+ </xsl:when>
+ </xsl:choose>
+ <xsl:call-template name="tokenize">
+ <xsl:with-param name="first" select="false()"/>
+ <xsl:with-param name="s" select="substring-after($s, $delim)"/>
+ <xsl:with-param name="delim" select="$delim"/>
+ <xsl:with-param name="prefix" select="$prefix"/>
+ <xsl:with-param name="suffix" select="$suffix"/>
+ <xsl:with-param name="separator" select="$separator"/>
+ <xsl:with-param name="action" select="$action"/>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:choose>
+ <xsl:when test="$action = 'output'">
+ <xsl:if test="$first != true()">
+ <xsl:value-of select="$separator"/>
+ </xsl:if>
+ <xsl:value-of select="$prefix"/>
+ <xsl:value-of select="$s"/>
+ <xsl:value-of select="$suffix"/>
+ </xsl:when>
+ </xsl:choose>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+</xsl:stylesheet>
diff --git a/sudoers2xml b/sudoers/sudoers2xml
index 4ce9b18..4ce9b18 100644
--- a/sudoers2xml
+++ b/sudoers/sudoers2xml
diff --git a/sudoers/ttygroup.rng b/sudoers/ttygroup.rng
new file mode 100644
index 0000000..c8dfce6
--- /dev/null
+++ b/sudoers/ttygroup.rng
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<grammar xmlns="http://relaxng.org/ns/structure/1.0"
+ datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"
+ xmlns:a="http://freeipa.org/xml/rng/ns/annotations/1.0">
+
+ <a:doc> ttygroup configuration</a:doc>
+
+ <start ns="http://freeipa.org/xml/rng/ttygroup/1.0">
+ <element name="ttygroup">
+ <ref name="options"/>
+ <ref name="anyElement"/>
+ </element>
+
+ </start>
+
+ <define name="options">
+ <zeroOrMore>
+ <choice>
+ <attribute name="terminals">
+ <text/>
+ </attribute>
+ </choice>
+ </zeroOrMore>
+ </define>
+ <!--
+ This allows anything in another namespace.
+ The way nsName works requires that this be in each schema (grammar);
+ it cannot be included.
+ -->
+ <define name="anyElement">
+ <element>
+ <anyName>
+ <except>
+ <nsName/>
+ <nsName ns=""/>
+ </except>
+ </anyName>
+ <zeroOrMore>
+ <choice>
+ <attribute>
+ <anyName/>
+ </attribute>
+ <text/>
+ <ref name="anyElement"/>
+ </choice>
+ </zeroOrMore>
+ </element>
+ </define>
+</grammar>
diff --git a/sudoers/user.rng b/sudoers/user.rng
new file mode 100644
index 0000000..b0aec32
--- /dev/null
+++ b/sudoers/user.rng
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<grammar xmlns="http://relaxng.org/ns/structure/1.0"
+ datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"
+ xmlns:a="http://freeipa.org/xml/rng/ns/annotations/1.0">
+
+ <a:doc> user configuration</a:doc>
+
+ <start ns="http://freeipa.org/xml/rng/user/1.0">
+ <element name="user">
+ <ref name="options"/>
+ <ref name="anyElement"/>
+ </element>
+
+ </start>
+
+ <define name="options">
+ <zeroOrMore>
+ <choice>
+ <attribute name="uids">
+ <text/>
+ </attribute>
+ </choice>
+ </zeroOrMore>
+ </define>
+ <!--
+ This allows anything in another namespace.
+ The way nsName works requires that this be in each schema (grammar);
+ it cannot be included.
+ -->
+ <define name="anyElement">
+ <element>
+ <anyName>
+ <except>
+ <nsName/>
+ <nsName ns=""/>
+ </except>
+ </anyName>
+ <zeroOrMore>
+ <choice>
+ <attribute>
+ <anyName/>
+ </attribute>
+ <text/>
+ <ref name="anyElement"/>
+ </choice>
+ </zeroOrMore>
+ </element>
+ </define>
+</grammar>
diff --git a/sudoers/username.rng b/sudoers/username.rng
new file mode 100644
index 0000000..9b3f37f
--- /dev/null
+++ b/sudoers/username.rng
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<grammar xmlns="http://relaxng.org/ns/structure/1.0"
+ datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"
+ xmlns:a="http://freeipa.org/xml/rng/ns/annotations/1.0">
+ <define name="username_pattern" combine="choice">
+ <data type="string">
+ <param name="pattern">[A-Za-z0-9_-]{1,16}</param>
+ </data>
+ </define>
+</grammar>
+