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