<div dir="ltr">Food for thought/test, since it is not clear in the sudoers manual (but I'm sure it is currently wrong in the lens I wrote today):<br><br>What is the correct representation of <br>USER NET1, NET2=(RUNAS1, RUNAS2) NOPASSWD: EXEC: /bin/cmd1, NOEXEC: /bin/cmd2, (RUNAS3) /bin/cmd3 : NET3 = CMD<br>
<br>?<br><br>I can go as far as representing it as <br>{ "spec"<br>    { "user" = "USER" }<br>    { "host_group"<br>        { "host" = "NET1" }<br>        { "host" = "NET2" }<br>
        { "runas_group"<br>            { "runas_user" = "RUNAS1" }<br>            { "runas_user" = "RUNAS2" }<br>            { "tag" = "NOPASSWD"<br>                { "tag" = "EXEC"<br>
                    { "command" = "/bin/cmd1" } } }<br>            { "tag" = "NOEXEC"<br>                { "command" = "/bin/cmd2" } }<br>        { "runas_group"<br>
            { "runas_user" = "RUNAS3"<br>                { "command" = "/bin/cmd3" } } } }<br>    { "host_group"<br>        { "host" = "NET3" }<br>            { "command" = "CMD" } } }<br>
<br><br>Now now... that's very tricky. Here are a few comments:<br>* commands can appear at a lot of different levels... I think it would be better if I could list commands on top and have all the rest be properties of commands, but I'm afraid I can't do that currently with augeas since I can't remember a value parsed beforehand.<br>
* I'm not even sure this is correct. The manpages are very good, but I can't tell if this is right. It may well be that NOPASSWD is kept for /bin/cmd2, and even for CMD. I have no idea!<br><br>Any thoughts on this? Any sudo expert around?<br>
<br><br>Raphael<br><br><br><div class="gmail_quote">On Mon, Aug 11, 2008 at 7:07 PM, Raphaël Pinson <span dir="ltr"><<a href="mailto:raphink@gmail.com">raphink@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
<div dir="ltr">Hi guys,<br><br><br>I've been trying to have a look at a lens for sudoers. I expected it to be challenging, and so it is. Thankfully, man sudoers is one of the best conffile docs ever.<br><br>Here is the code I have so far. It has a few major problems:<br>

* augparse takes a few seconds to check it<br>* it doesn't support "\" to continue a line. This is the biggest issue, and I have no idea how to fix that in augeas.<br><br><br>sudoers.aug :<br><br>=========================================================<br>

(* Sudoers module for Augeas                  *)<br>(* Author: Raphael Pinson <<a href="mailto:raphink@gmail.com" target="_blank">raphink@gmail.com</a>> *)<br>(*                                            *)<br>(* Reference: `man sudoers`                   *)<br>

<br><br>module Sudoers =<br>  autoload xfm<br><br>    (* Define useful shortcuts *)<br><br>    let eol       = del /[ \t]*\n/ "\n"<br><br>    (* Define separators *)<br>    let sep_com = del /[ \t]*,[ \t]*/ ", "<br>

    let sep_eq  = del /[ \t]*=[ \t]*/ " = "<br>    let sep_spc = del /[ \t]+/ " "<br>    let sep_col = del /[ \t]*:[ \t]*/ " : "<br><br>    (* Define fields *)<br>    (* sto_to_com does not begin or end with a space *)<br>

    let sto_to_com_cmnd = store /([^,=:#() \t\n][^,=:#()\n]*[^,=:#() \t\n])|[^,=:#() \t\n]/<br>    let sto_to_com      = store /[^,=:#() \t\n]+/<br>    let sto_to_com_user = store ( /[^,=:#() \t\n]+/ - /(User|Runas|Host|Cmnd)_Alias|Defaults/ )<br>

    let sto_to_eq  = store /[^,=:#() \t\n]+/<br>    let sto_to_spc = store /[^() \t\n]+/<br><br><br>    (* define comments and empty lines *)<br>    let comment =<br>        let value_to_eol = del /[ \t]*/ " " . store /([^ \t\n].*[^ \t\n]|[^ \t\n])/ in<br>

        [ label "comment" . del /[ \t]*#/ "# " .  value_to_eol? . eol ]<br><br>    let empty   = [ del /[ \t]*\n/ "" ]<br><br><br>    (* define aliases *)<br><br>    (* General definitions *)<br>

    let alias_field (kw:string) (sto:lens) = [ label kw . sto ]<br>    let alias_list  (kw:string) (sto:lens) = alias_field kw sto . ( sep_com . alias_field kw sto )*<br>    let alias_entry (kw:string) (field:string) (sto:lens) = [ key kw . sep_spc . sto_to_eq . sep_eq . alias_list field sto . eol ]<br>

<br>    (* TODO: go further in user definitions *)<br>    let user_alias  = alias_entry "User_Alias" "user" sto_to_com<br>    let runas_alias = alias_entry "Runas_Alias" "runas_user" sto_to_com<br>

    let host_alias  = alias_entry "Host_Alias" "host" sto_to_com<br>    let cmnd_alias  = alias_entry "Cmnd_Alias" "command" sto_to_com_cmnd<br><br>    let alias = user_alias | runas_alias | host_alias | cmnd_alias<br>

<br><br>    (* define defaults *)<br>    let default_type     =<br>        let value = store /(@|:|>)[^ \t\n]+/ in<br>        [ label "type" . value ]<br>    let parameter        = [ label "parameter" . sto_to_com ]<br>

    let parameter_list   = parameter . ( sep_com . parameter )*<br>    let defaults = [ key "Defaults" . default_type? . sep_spc . parameter_list . eol ]<br><br><br>    (* define spec *)<br><br>    let runas_spec = Util.del_str "(" . alias_list "runas_user" sto_to_com . Util.del_str ")" . sep_spc<br>

    let tag_spec   = [ label "tag" . store /(NO)?(PASSWD|EXEC|SETENV)/ . Util.del_str ":" ] . sep_spc<br>    let cmnd       = sto_to_com<br>    let cmnd_spec  = [ label "command" .  runas_spec? . tag_spec* . cmnd ]<br>

    let cmnd_spec_list = cmnd_spec . ( sep_com . cmnd_spec )*<br><br>    let spec_list = [ seq "list" . alias_list "host" sto_to_com . sep_eq . cmnd_spec_list ]<br><br>    let spec = [ label "spec" . counter "list"<br>

                              . alias_list "user" sto_to_com_user . sep_spc<br>                              . spec_list<br>                              . ( sep_col . spec_list )* . eol ]<br><br><br>    let lns = ( empty | comment | alias | defaults | spec  )*<br>

<br>    let filter = (incl "/etc/sudoers")<br>        . Util.stdexcl<br><br>    let xfm = transform lns filter<br><br>=========================================================<br><br>test_sudoers.aug<br><br>=========================================================<br>

<br>module Test_sudoers =<br><br>   let conf = "<br>Host_Alias LOCALNET = <a href="http://192.168.0.0/24" target="_blank">192.168.0.0/24</a>, localhost<br><br># User alias specification<br><br># Cmnd alias specification<br>
<br>Cmnd_Alias DEBIAN_TOOLS = /usr/bin/apt-get, /usr/bin/auto-get,        /usr/bin/dpkg, /usr/bin/dselect, /usr/sbin/dpkg-reconfigure<br>
<br>Cmnd_Alias PBUILDER = /usr/sbin/pbuilder<br><br>Cmnd_Alias ICAL = /bin/cat /home/rpinson/.kde/share/apps/korganizer/std.ics<br><br>Defaults@LOCALNET        !lecture,tty_tickets,!fqdn<br><br># User privilege specification<br>

root    ALL=(ALL) ALL<br><br># Members of the admin group may gain root privileges<br>%admin  ALL=(ALL) ALL, NOPASSWD: DEBIAN_TOOLS<br>%pbuilder       LOCALNET = NOPASSWD: PBUILDER<br>www-data ALL=(rpinson) NOEXEC: ICAL : localhost = NOPASSWD:     /usr/bin/test<br>

"<br><br>   test Sudoers.lns get conf =<br>      {}<br>      { "Host_Alias" = "LOCALNET"<br>          { "host" = "<a href="http://192.168.0.0/24" target="_blank">192.168.0.0/24</a>" }<br>
          { "host" = "localhost" } }<br>
      {}<br>      { "comment" = "User alias specification" }<br>      {}<br>      { "comment" = "Cmnd alias specification" }<br>      {}<br>      { "Cmnd_Alias" = "DEBIAN_TOOLS"<br>

          { "command" = "/usr/bin/apt-get" }<br>          { "command" = "/usr/bin/auto-get" }<br>          { "command" = "/usr/bin/dpkg" }<br>          { "command" = "/usr/bin/dselect" }<br>

          { "command" = "/usr/sbin/dpkg-reconfigure" } }<br>      {}<br>      { "Cmnd_Alias" = "PBUILDER"<br>          { "command" = "/usr/sbin/pbuilder" } }<br>

      {}<br>      { "Cmnd_Alias" = "ICAL"<br>          { "command" = "/bin/cat /home/rpinson/.kde/share/apps/korganizer/std.ics" } }<br>      {}<br>      { "Defaults"<br>
          { "type"      = "@LOCALNET" }<br>
          { "parameter" = "!lecture" }<br>          { "parameter" = "tty_tickets" }<br>          { "parameter" = "!fqdn" } }<br>      {}<br>      { "comment" = "User privilege specification" }<br>

      { "spec"<br>          { "user" = "root" }<br>          { "1"<br>              { "host" = "ALL" }<br>              { "command" = "ALL"<br>

                  { "runas_user"  = "ALL" } } } }<br>      {}<br>      { "comment" = "Members of the admin group may gain root privileges" }<br>      { "spec"<br>          { "user"    = "%admin" }<br>

          { "1"<br>              { "host" = "ALL" }<br>              { "command" = "ALL"<br>                  { "runas_user" = "ALL" } }<br>              { "command" = "DEBIAN_TOOLS"<br>

                  { "tag"  = "NOPASSWD" } } } }<br>      { "spec"<br>          { "user"    = "%pbuilder" }<br>          { "1"<br>              { "host" = "LOCALNET" }<br>

              { "command" = "PBUILDER"<br>                  { "tag" = "NOPASSWD" } } } }<br>      { "spec"<br>          { "user"    = "www-data" }<br>
          { "1"<br>
              { "host" = "ALL" }<br>              { "command" = "ICAL"<br>                  { "runas_user" = "rpinson" }<br>                  { "tag" = "NOEXEC" } } }<br>

          { "2"<br>              { "host" = "localhost" }<br>              { "command" = "/usr/bin/test"<br>                  { "tag" = "NOPASSWD" } } } }<br>

<br><br>=========================================================<br></div>
</blockquote></div><br></div>