diff options
author | Sumit Bose <sbose@nb.localdomain> | 2008-09-18 10:46:33 +0200 |
---|---|---|
committer | Sumit Bose <sbose@nb.localdomain> | 2008-09-18 10:46:33 +0200 |
commit | 7bfb88bbf648000b4c2bf853a11ad2bd3f4b2d85 (patch) | |
tree | b5e5bf2cd5768dd129d23fb76cb30304cd5315e5 /sudoers | |
parent | 575f23f9ca93b302cb487c037edcbb8bf7554437 (diff) | |
download | ipa_policy-7bfb88bbf648000b4c2bf853a11ad2bd3f4b2d85.tar.gz ipa_policy-7bfb88bbf648000b4c2bf853a11ad2bd3f4b2d85.tar.xz ipa_policy-7bfb88bbf648000b4c2bf853a11ad2bd3f4b2d85.zip |
added fcusack's work
Diffstat (limited to 'sudoers')
-rw-r--r-- | sudoers/ipa.rng | 42 | ||||
-rw-r--r-- | sudoers/netgroup.rng | 49 | ||||
-rw-r--r-- | sudoers/options.rng | 448 | ||||
-rw-r--r-- | sudoers/posixGroup.rng | 49 | ||||
-rw-r--r-- | sudoers/sudoOptions.rng | 73 | ||||
-rw-r--r-- | sudoers/sudoers.rng | 64 | ||||
-rw-r--r-- | sudoers/sudoers.xslt | 566 | ||||
-rw-r--r-- | sudoers/sudoers2xml | 214 | ||||
-rw-r--r-- | sudoers/ttygroup.rng | 49 | ||||
-rw-r--r-- | sudoers/user.rng | 49 | ||||
-rw-r--r-- | sudoers/username.rng | 11 |
11 files changed, 1614 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

</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="'
'"/> + </xsl:call-template> + + <xsl:text>
</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>
</xsl:text> + </xsl:with-param> + <xsl:with-param name="separator" select="''"/> + </xsl:call-template> + + <xsl:text>
</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/sudoers/sudoers2xml b/sudoers/sudoers2xml new file mode 100644 index 0000000..4ce9b18 --- /dev/null +++ b/sudoers/sudoers2xml @@ -0,0 +1,214 @@ +#!/usr/bin/env perl +use strict; +use feature 'state'; +use Data::Dumper; +# +# Converts a sudoers file to LDIF format in prepration for loading into +# the LDAP server. +# +# $Sudo: sudoers2ldif,v 1.2.2.1 2007/06/28 14:45:19 millert Exp $ +# + +# BUGS: +# Does not yet handle multiple lines with : in them +# Does not yet remove quotation marks from options +# Does not yet escape + at the beginning of a dn +# Does not yet handle line wraps correctly +# Does not yet handle multiple roles with same name (needs tiebreaker) +# Sudoers entries can have multiple Runas entries that override former ones, +# with LDAP sudoRunas applies to all commands in a sudoRole + +my %UA; +my %HA; +my %CA; +my %RA; +##my $base=$ENV{SUDOERS_BASE} or die "$0: Container SUDOERS_BASE undefined\n"; +my @options=(); + +my %user_group_namespaces=(); +$user_group_namespaces{'netgroup'}='xmlns="http://freeipa.org/xml/rng/netgroup/1.0"'; +$user_group_namespaces{'posixGroup'}='xmlns="http://freeipa.org/xml/rng/posixGroup/1.0"'; +$user_group_namespaces{'user'}='xmlns="http://freeipa.org/xml/rng/user/1.0"'; +my %user_group_attributename=(); +$user_group_attributename{'netgroup'}='groupnames'; +$user_group_attributename{'posixGroup'}='gids'; +$user_group_attributename{'user'}='uids'; + +my $did_defaults=0; + +print '<?xml version="1.0" encoding="UTF-8"?>'."\n"; +print '<ipa xmlns="http://freeipa.org/xml/rng/ipa/1.0">'."\n"; + +# parse sudoers one line at a time +while (<>){ + + # remove comment + s/#.*//; + + # line continuation + $_.=<> while s/\\\s*$//s; + + # cleanup newline + chomp; + + # ignore blank lines + next if /^\s*$/; + + if (/^Defaults\s+/i) { + my $opt=$'; + $opt=~s/\s+$//; # remove trailing whitespace + push @options,$opt; + } elsif (/^Defaults[:@>]/i) { + #ignore + my $opt=$'; + } elsif (/^(\S+)\s+(.+)=\s*(.*)/) { + + # Aliases or Definitions + my ($p1,$p2,$p3)=($1,$2,$3); + $p2=~s/\s+$//; # remove trailing whitespace + $p3=~s/\s+$//; # remove trailing whitespace + + if ($p1 eq "User_Alias") { + $UA{$p2}=$p3; + } elsif ($p1 eq "Host_Alias") { + $HA{$p2}=$p3; + } elsif ($p1 eq "Cmnd_Alias") { + $CA{$p2}=$p3; + } elsif ($p1 eq "Runas_Alias") { + $RA{$p2}=$p3; + } else { + if (!$did_defaults++){ + # do this once + ##print "dn: cn=defaults,$base\n"; + ##print "objectClass: top\n"; + ##print "objectClass: sudoRole\n"; + ##print "cn: defaults\n"; + ##print "description: Default sudoOption's go here\n"; + ##print "sudoOption: $_\n" foreach @options; + print '<sudoOptions xmlns="http://freeipa.org/xml/rng/sudo/sudoOptions/1.0" '; + #print "$_ " foreach @options; + foreach ( split /,/, (join ',', @options) ) { + $_ =~ s/=(.*)/=\"$1\"/; + print "$_ "; + } + print "/>\n"; + print "\n"; + } + # Definition + my @users=split /\s*,\s*/,$p1; + my @hosts=split /\s*,\s*/,$p2; + $p3 =~ s/\\,/\\#/g; + my @cmds= split /\s*,\s*/,$p3; + s/\\#/,/g foreach @cmds; + @options=(); + foreach my $user (expand(\%UA, @users)) { + my $type="user"; + $type="posixGroup" if $user =~ s/^%//; + $type="netgroup" if $user =~ s/^\+//; + print "<$type $user_group_namespaces{$type} $user_group_attributename{$type}=\"$user\">\n"; + tl(1); + # only "global" user options here!!! + #if (@options) { + # print tl() . '<sudoOptions xmlns="http://freeipa.org/xml/rng/sudo/sudoOptions/1.0"'; + # print "$_ " foreach @options; + # print "/>\n"; + #} + print tl() . '<sudoers xmlns="http://freeipa.org/xml/rng/sudo/sudoers/1.0">'."\n"; + tl(1); +#print Dumper(%CA, @cmds); + my @mycmds=@cmds; + #foreach my $command (expand(\%CA,@cmds)) { + foreach my $command (@mycmds) { + my $runas=''; + if ( $command =~ s/^\(([^\)]+)\)\s*//) { + $runas .= "<runas>$_</runas>" foreach expand(\%RA, split(/,\s*/, $1)); + } + foreach (expand(\%CA,$command)) { + my $tag=''; + if (@options) { + $tag = '<tag>'; + $tag .= "$_ " foreach @options; + $tag =~ s/ $/<\/tag>/; + } + print tl() . "<command><path>$_</path>$tag$runas</command>\n" + } + @options=(); + } + tl(-1); + print tl() . "</sudoers>\n"; + tl(-1); + ##print "dn: cn=$users[0],$base\n"; + ##print "objectClass: top\n"; + ##print "objectClass: sudoRole\n"; + ##print "cn: $users[0]\n"; + # will clobber options + ##print "sudoUser: $_\n" foreach expand(\%UA,@users); + ##print "sudoHost: $_\n" foreach expand(\%HA,@hosts); + ##my $runas = undef; + ##foreach (@cmds) { + ##if (s/^\(([^\)]+)\)\s*//) { + ##print "sudoRunas: $_\n" foreach expand(\%UA, split(/,\s*/, $1)); + ##} + ##} + ##print "sudoCommand: $_\n" foreach expand(\%CA,@cmds); + ##print "sudoOption: $_\n" foreach @options; + print "</$type>\n"; + print "\n"; + } + } + + } else { + print "parse error: $_\n"; + } + +} +print '</ipa>'."\n"; + +# +# recursively expand hash elements +sub expand{ + my $ref=shift; + my @a=(); + + # preen the line a little + foreach (@_){ + # if NOPASSWD: directive found, mark entire entry as not requiring + s/NOPASSWD:\s*// && push @options,'NOPASSWD'; + s/PASSWD:\s*// && push @options,'PASSWD'; + s/NOEXEC:\s*// && push @options,"NOEXEC"; + s/EXEC:\s*// && push @options,"EXEC"; + s/SETENV:\s*// && push @options,"SETENV"; + s/NOSETENV:\s*// && push @options,"NOSETENV"; + s/\w+://; # silently remove other directives + s/\s+$//; # right trim + } + + # do the expanding + #push @a,$ref->{$_} ? expand($ref,split /\s*,\s*/,$ref->{$_}):$_ foreach @_; + foreach (@_) { + if ( s/^!// ) { + my @dummy = $ref->{$_} ? expand($ref,split /\s*,\s*/,$ref->{$_}):$_; + s/^/!/ foreach @dummy; + push @a, @dummy; + } else { + push @a, $ref->{$_} ? expand($ref,split /\s*,\s*/,$ref->{$_}):$_; + } + } + @a; +} + +sub tl { + my $d = @_?$_[0]:0; + + state $tablevel=0; + +#print $d."\n"; +#print "t=" . $tablevel."\n"; + + $tablevel += $d; +#print "t2=" . $tablevel."\n"; + $tablevel=0 if ( $tablevel < 0 ); +#print "t3=" . $tablevel."\n"; + + return "\t" x $tablevel; +} 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> + |