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