<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">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">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">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>