diff --git a/.augeas.metadata b/.augeas.metadata new file mode 100644 index 0000000..066252a --- /dev/null +++ b/.augeas.metadata @@ -0,0 +1 @@ +27b563bb173eed6163d76b5b21f3a1566c82351b SOURCES/augeas-1.4.0.tar.gz diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..eeed9c4 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +SOURCES/augeas-1.4.0.tar.gz diff --git a/SOURCES/0001-Syslog-restored-Augeas-1.1.0-tree-compatibility-for-.patch b/SOURCES/0001-Syslog-restored-Augeas-1.1.0-tree-compatibility-for-.patch new file mode 100644 index 0000000..9a5e106 --- /dev/null +++ b/SOURCES/0001-Syslog-restored-Augeas-1.1.0-tree-compatibility-for-.patch @@ -0,0 +1,101 @@ +From 706266780350ba61d36ec387dc18e9f4764ed872 Mon Sep 17 00:00:00 2001 +From: Yanis Guenane +Date: Sun, 8 Sep 2013 09:30:17 -0400 +Subject: [PATCH] Syslog: restored Augeas 1.1.0 tree compatibility for UDP + hosts + +UDP host entries don't require the { "protocol" = "@" } node, it's only +used for TCP hosts. +--- + lenses/syslog.aug | 10 +++++++--- + lenses/tests/test_rsyslog.aug | 1 - + lenses/tests/test_syslog.aug | 7 +++---- + 3 files changed, 10 insertions(+), 8 deletions(-) + +diff --git a/lenses/syslog.aug b/lenses/syslog.aug +index f8b99c40..17c0f903 100644 +--- a/lenses/syslog.aug ++++ b/lenses/syslog.aug +@@ -66,6 +66,10 @@ module Syslog = + Deletes a semicolon and default to it + *) + let semicolon = sep_tab_opt . Util.del_str ";" . sep_tab_opt ++ (* Variable: at ++ Deletes a at and default to it ++ *) ++ let at = Util.del_str "@" + (* Variable: dot + Deletes a dot and default to it + *) +@@ -105,10 +109,10 @@ module Syslog = + let comparison = /(!|[<=>]+|![<=>]+)/ + + (* Variable: protocol +- @ means UDP ++ @ means UDP (removed, no protocol node is used for compatibility with 1.1.0) + @@ means TCP + *) +- let protocol = /@{1,2}/ ++ let protocol = /@@/ + + (* Variable: token + alphanum or "*" +@@ -185,7 +189,7 @@ module Syslog = + (* View: loghost + a loghost is an @ sign followed by the hostname and a possible port + *) +- let loghost = [label "protocol" . store protocol] . [ label "hostname" . store loghost_r ] . ++ let loghost = ([label "protocol" . store protocol] | at) . [ label "hostname" . store loghost_r ] . + (colon . [ label "port" . store /[0-9]+/ ] )? + + (* View: users +diff --git a/lenses/tests/test_rsyslog.aug b/lenses/tests/test_rsyslog.aug +index e696139c..46b24c3c 100644 +--- a/lenses/tests/test_rsyslog.aug ++++ b/lenses/tests/test_rsyslog.aug +@@ -86,7 +86,6 @@ test Rsyslog.lns get conf = + { "level" = "*" } + } + { "action" +- { "protocol" = "@" } + { "hostname" = "2.7.4.1" } + } + } +diff --git a/lenses/tests/test_syslog.aug b/lenses/tests/test_syslog.aug +index 2ad1c165..329d121e 100644 +--- a/lenses/tests/test_syslog.aug ++++ b/lenses/tests/test_syslog.aug +@@ -91,11 +91,11 @@ daemon.info /var/log/cvsupd.log + } + { "entry" + { "selector" { "facility" = "*" } { "level" = "*" } } +- { "action" { "protocol" = "@" } { "hostname" = "syslog.far.away" } } ++ { "action" { "hostname" = "syslog.far.away" } } + } + { "entry" + { "selector" { "facility" = "*" } { "level" = "*" } } +- { "action" { "protocol" = "@" } { "hostname" = "syslog.far.away" } { "port" = "123" } } ++ { "action" { "hostname" = "syslog.far.away" } { "port" = "123" } } + } + { "entry" + { "selector" { "facility" = "*" } { "level" = "*" } } +@@ -107,7 +107,7 @@ daemon.info /var/log/cvsupd.log + } + { "entry" + { "selector" { "facility" = "*" } { "level" = "*" } } +- { "action" { "protocol" = "@" } { "hostname" = "[2001::1]" } { "port" = "514" } } ++ { "action" { "hostname" = "[2001::1]" } { "port" = "514" } } + } + { "entry" + { "selector" { "facility" = "*" } { "level" = "*" } } +@@ -260,7 +260,6 @@ daemon.info /var/log/cvsupd.log + (* changing file to remote host *) + test Syslog.lns put "*.* /var\n" after + rm "/entry/action/file" ; +- set "/entry/action/protocol" "@" ; + set "/entry/action/hostname" "far.far.away" + = "*.* @far.far.away\n" + +-- +2.17.2 + diff --git a/SOURCES/0002-Revert-Use-Quote-module-in-dovecot.patch b/SOURCES/0002-Revert-Use-Quote-module-in-dovecot.patch new file mode 100644 index 0000000..c249934 --- /dev/null +++ b/SOURCES/0002-Revert-Use-Quote-module-in-dovecot.patch @@ -0,0 +1,86 @@ +From 2765da41b09cdfcf2f28653a484462ee7109116a Mon Sep 17 00:00:00 2001 +From: Dominic Cleal +Date: Fri, 12 Jun 2015 09:32:56 +0100 +Subject: [PATCH] Revert "Use Quote module in dovecot" + +This reverts commit 735caf587959019d214a51a7c0cce57da9bb88f6 for +compatibility with Augeas 1.1.0. + +Values will have quotes in them as they did in 1.1.0, not stripped out. + +Conflicts: + lenses/dovecot.aug +--- + lenses/dovecot.aug | 28 +++++----------------------- + lenses/tests/test_dovecot.aug | 2 +- + 2 files changed, 6 insertions(+), 24 deletions(-) + +diff --git a/lenses/dovecot.aug b/lenses/dovecot.aug +index f7afc8f9..c6376e4b 100644 +--- a/lenses/dovecot.aug ++++ b/lenses/dovecot.aug +@@ -56,6 +56,9 @@ let value = any . (Rx.space . any)* + (* View: command_start *) + let command_start = Util.del_str "!" + ++(* View: block_args ++Map block arguments after block name and before "{" *) ++let block_args = Sep.space . store /([A-Za-z0-9\/\\_-]+|\"[A-Za-z0-9 ]*\")/ + + (****************************************************************** + * Group: ENTRIES +@@ -79,28 +82,7 @@ let entry = [ indent . key keys. eq . (Sep.opt_space . store value)? . eol ] + Map commands started with "!". *) + let command = [ command_start . key commands . Sep.space . store Rx.fspath . eol ] + +-(* +-View: dquote_spaces +- Make double quotes mandatory if value contains spaces, +- and optional if value doesn't contain spaces. +- +-Based off Quote.dquote_spaces +- +-Parameters: +- lns1:lens - the lens before +- lns2:lens - the lens after +-*) +-let dquote_spaces (lns1:lens) (lns2:lens) = +- (* bare has no spaces, and is optionally quoted *) +- let bare = Quote.do_dquote_opt (store /[^" \t\n]+/) +- (* quoted has at least one space, and must be quoted *) +- in let quoted = Quote.do_dquote (store /[^"\n]*[ \t]+[^"\n]*/) +- in [ lns1 . bare . lns2 ] | [ lns1 . quoted . lns2 ] +- +-let mailbox = indent +- . dquote_spaces +- (key /mailbox/ . Sep.space) +- (Build.block_newlines_spc entry comment . eol) ++let mailbox = [ indent . key /mailbox/ . block_args? . Build.block_newlines_spc (entry) comment . eol ] + + let block_ldelim_newlines_re = /[ \t]+\{([ \t\n]*\n)?/ + +@@ -114,7 +96,7 @@ let block_newlines (entry:lens) (comment:lens) = + Map block enclosed in brackets recursively. + Block may be indented and have optional argument. + Block body may have entries, comments, empty lines, and nested blocks recursively. *) +-let rec block = [ indent . key block_names . (Sep.space . Quote.do_dquote_opt (store /[\/A-Za-z0-9_-]+/))? . block_newlines (entry|block|mailbox) comment . eol ] ++let rec block = [ indent . key block_names . block_args? . block_newlines (entry|block|mailbox) comment . eol ] + + + (****************************************************************** +diff --git a/lenses/tests/test_dovecot.aug b/lenses/tests/test_dovecot.aug +index 33ea16f1..8e8c083b 100644 +--- a/lenses/tests/test_dovecot.aug ++++ b/lenses/tests/test_dovecot.aug +@@ -536,7 +536,7 @@ test Dovecot.lns get mail_conf = + { "hidden" = "no" } + { "list" = "yes" } + { "subscriptions" = "yes" } +- { "mailbox" = "Sent Messages" ++ { "mailbox" = "\"Sent Messages\"" + { "special_use" = "\Sent" } + } + } +-- +2.17.2 + diff --git a/SOURCES/0003-Revert-Jaas-add-several-improvements-to-cover-more-v.patch b/SOURCES/0003-Revert-Jaas-add-several-improvements-to-cover-more-v.patch new file mode 100644 index 0000000..fed2fed --- /dev/null +++ b/SOURCES/0003-Revert-Jaas-add-several-improvements-to-cover-more-v.patch @@ -0,0 +1,143 @@ +From cd586dfa4ade4ea574aae0fa6ac034c07c77b25a Mon Sep 17 00:00:00 2001 +From: Dominic Cleal +Date: Fri, 12 Jun 2015 09:47:48 +0100 +Subject: [PATCH] Revert "Jaas: add several improvements to cover more valid + syntax" + +This partially reverts commit d17f2fbc30a52edb3719fc6df4c24f01552dd203 +for compatibility with Augeas 1.1.0. + +Trailing semicolons remain part of the last value. Only support for +"naked" booleans has been kept from 1.4.0. + +Conflicts: + NEWS +--- + lenses/jaas.aug | 29 ++++++++++++----------------- + lenses/tests/test_jaas.aug | 21 ++++++++++----------- + 2 files changed, 22 insertions(+), 28 deletions(-) + +diff --git a/lenses/jaas.aug b/lenses/jaas.aug +index 4f06bad9..a13682e3 100644 +--- a/lenses/jaas.aug ++++ b/lenses/jaas.aug +@@ -1,36 +1,31 @@ + (* Module Jaas *) +-(* Original Author: Simon Vocella *) +-(* Updated by: Steve Shipway *) +-(* Changes: allow comments within Modules, allow optionless flags, *) +-(* allow options without linebreaks, allow naked true/false options *) +-(* Trailing ';' terminator should not be included in option value *) +-(* Note: requires latest Util.aug for multiline comments to work *) ++(* Author: Simon Vocella *) + + module Jaas = + + autoload xfm + + let space_equal = del (/[ \t]*/ . "=" . /[ \t]*/) (" = ") +-let lbrace = del (/[ \t\n]*\{[ \t]*\n/) " {\n" +-let rbrace = del (/[ \t]*}[ \t]*;/) " };" ++let lbrace = del (/[ \t\n]*/ . "{") "{" ++let rbrace = del ("};") "};" + let word = /[A-Za-z0-9_.-]+/ +-let wsnl = del (/[ \t\n]+/) ("\n") +-let endflag = del ( /[ \t]*;/ ) ( ";" ) ++let wordonly = /[A-Za-z0-9_.-]+;/ + + let value_re = + let value_squote = /'[^\n']*'/ ++ in let value_squote_2 = /'[^\n']*';/ + in let value_dquote = /"[^\n"]*"/ +- in let value_tf = /(true|false)/ +- in value_squote | value_dquote | value_tf ++ in let value_dquote_2 = /"[^\n"]*";/ ++ in let value_tf = /(true|false);/ ++ in let value_tf_2 = /(true|false);/ ++ in value_squote | value_squote_2 | value_dquote | value_dquote_2 | value_tf | value_tf_2 + +-let moduleOption = [ wsnl . key word . space_equal . (store value_re) ] +-let moduleSuffix = ( moduleOption | Util.eol . Util.comment_c_style | Util.comment_multiline ) +-let flag = [ Util.del_ws_spc . label "flag" . (store word) . moduleSuffix* . endflag ] +-let loginModuleClass = [( Util.del_opt_ws "" . label "loginModuleClass" . (store word) . flag ) ] ++let moduleOption = [Util.del_opt_ws "" . key word . space_equal . (store value_re . Util.comment_or_eol)] ++let flag = [label "flag" . ((store word . Util.eol . moduleOption+) | (store wordonly . Util.eol))] ++let loginModuleClass = [Util.del_opt_ws "" . label "loginModuleClass" . (store word . Util.del_ws_spc) . flag] + + let content = (Util.empty | Util.comment_c_style | Util.comment_multiline | loginModuleClass)* + let loginModule = [Util.del_opt_ws "" . label "login" . (store word . lbrace) . (content . rbrace)] +- + let lns = (Util.empty | Util.comment_c_style | Util.comment_multiline | loginModule)* + let filter = incl "/opt/shibboleth-idp/conf/login.config" + let xfm = transform lns filter +diff --git a/lenses/tests/test_jaas.aug b/lenses/tests/test_jaas.aug +index 5f2bfb13..d5ede698 100644 +--- a/lenses/tests/test_jaas.aug ++++ b/lenses/tests/test_jaas.aug +@@ -54,7 +54,6 @@ ShibUserPassAuth { + serviceCredential = \"ldappassword\" + ssl = \"false\" + userField = \"uid\" +- // Example comment within definition + subtreeSearch = \"true\"; + }; + +@@ -64,8 +63,9 @@ NetAccountAuth { + }; + + com.sun.security.jgss.krb5.initiate { +- // Test of omitted linebreaks and naked boolean +- com.sun.security.auth.module.Krb5LoginModule required useTicketCache=true; ++ // Test of naked boolean ++ com.sun.security.auth.module.Krb5LoginModule required ++ useTicketCache=true; + };" + + test Jaas.lns get conf = +@@ -89,6 +89,7 @@ test Jaas.lns get conf = + { } + { } + { "login" = "ShibUserPassAuth" ++ { } + { } + { "#comment" = "Example LDAP authentication" } + { "#comment" = "See: https://wiki.shibboleth.net/confluence/display/SHIB2/IdPAuthUserPass" } +@@ -116,29 +117,27 @@ test Jaas.lns get conf = + { "serviceCredential" = "\"ldappassword\"" } + { "ssl" = "\"false\"" } + { "userField" = "\"uid\"" } +- { "#comment" = "Example comment within definition" } +- { "subtreeSearch" = "\"true\"" } ++ { "subtreeSearch" = "\"true\";" } + } + } +- { } + } + { } + { } + { "login" = "NetAccountAuth" ++ { } + { "#comment" = "Test of optionless flag" } + { "loginModuleClass" = "nz.ac.auckland.jaas.Krb5LoginModule" +- { "flag" = "required" } ++ { "flag" = "required;" } + } +- { } + } + { } + { } + { "login" = "com.sun.security.jgss.krb5.initiate" +- { "#comment" = "Test of omitted linebreaks and naked boolean" } ++ { } ++ { "#comment" = "Test of naked boolean" } + { "loginModuleClass" = "com.sun.security.auth.module.Krb5LoginModule" + { "flag" = "required" +- { "useTicketCache" = "true" } ++ { "useTicketCache" = "true;" } + } + } +- { } + } +-- +2.17.2 + diff --git a/SOURCES/0004-UpdateDB-autoload-etc-updatedb.conf-with-Simplevars.patch b/SOURCES/0004-UpdateDB-autoload-etc-updatedb.conf-with-Simplevars.patch new file mode 100644 index 0000000..2964e9c --- /dev/null +++ b/SOURCES/0004-UpdateDB-autoload-etc-updatedb.conf-with-Simplevars.patch @@ -0,0 +1,51 @@ +From 898ea6cd04163b38aa59b0c3d9df23cf1837d425 Mon Sep 17 00:00:00 2001 +From: Dominic Cleal +Date: Fri, 12 Jun 2015 10:46:57 +0100 +Subject: [PATCH] UpdateDB: autoload /etc/updatedb.conf with Simplevars + +updatedb.conf was loaded with Simplevars in Augeas 1.1.0, so continue +for compatibility. Use aug_transform, augtool --transform etc. to use +the newer, different, UpdateDB lens. +--- + lenses/simplevars.aug | 1 + + lenses/updatedb.aug | 8 -------- + 2 files changed, 1 insertion(+), 8 deletions(-) + +diff --git a/lenses/simplevars.aug b/lenses/simplevars.aug +index ad9795f0..ff0602cc 100644 +--- a/lenses/simplevars.aug ++++ b/lenses/simplevars.aug +@@ -41,6 +41,7 @@ let lns = (Util.empty | Util.comment | entry)* + (* Variable: filter *) + let filter = incl "/etc/kernel-img.conf" + . incl "/etc/kerneloops.conf" ++ . incl "/etc/updatedb.conf" + . incl "/etc/wgetrc" + . incl "/etc/zabbix/*.conf" + . incl "/etc/audit/auditd.conf" +diff --git a/lenses/updatedb.aug b/lenses/updatedb.aug +index 40cd26fb..c7309b16 100644 +--- a/lenses/updatedb.aug ++++ b/lenses/updatedb.aug +@@ -22,8 +22,6 @@ About: Examples + + module UpdateDB = + +-autoload xfm +- + (* View: list + A list entry *) + let list = +@@ -41,9 +39,3 @@ let bool = [ key "PRUNE_BIND_MOUNTS" . Sep.space_equal + (* View: lns + The lens *) + let lns = (Util.empty|Util.comment|list|bool)* +- +-(* Variable: filter +- The filter *) +-let filter = incl "/etc/updatedb.conf" +- +-let xfm = transform lns filter +-- +2.17.2 + diff --git a/SOURCES/0005-Revert-Dnsmasq-add-structure-to-address-and-server-o.patch b/SOURCES/0005-Revert-Dnsmasq-add-structure-to-address-and-server-o.patch new file mode 100644 index 0000000..9020437 --- /dev/null +++ b/SOURCES/0005-Revert-Dnsmasq-add-structure-to-address-and-server-o.patch @@ -0,0 +1,138 @@ +From 94b0373abfcb4a6474ee9bb7866fe28f9bbe876d Mon Sep 17 00:00:00 2001 +From: Dominic Cleal +Date: Fri, 12 Jun 2015 10:48:58 +0100 +Subject: [PATCH] Revert "Dnsmasq: add structure to 'address' and 'server' + options" + +This reverts commit 3e20740056bd548f714cd50e4adc6b76a249ddfc for tree +compatibility with Augeas 1.1.0. address and server options will be +unstructured. + +Conflicts: + NEWS +--- + lenses/dnsmasq.aug | 34 +++++++------------------ + lenses/tests/test_dnsmasq.aug | 47 ----------------------------------- + 2 files changed, 9 insertions(+), 72 deletions(-) + +diff --git a/lenses/dnsmasq.aug b/lenses/dnsmasq.aug +index f7ef9070..e19aab83 100644 +--- a/lenses/dnsmasq.aug ++++ b/lenses/dnsmasq.aug +@@ -17,42 +17,26 @@ module Dnsmasq = + * USEFUL PRIMITIVES + *************************************************************************) + +-let eol = Util.eol +-let spc = Util.del_ws_spc +-let comment = Util.comment +-let empty = Util.empty ++let eol = Util.eol ++let spc = Util.del_ws_spc ++let comment = Util.comment ++let empty = Util.empty + +-let sep_eq = Sep.equal +-let sto_to_eol = store /([^ \t\n].*[^ \t\n]|[^ \t\n])/ +- +-let slash = Util.del_str "/" +-let sto_no_slash = store /([^\/ \t\n]+)/ +-let domains = slash . [ label "domain" . sto_no_slash . slash ]+ ++let sep_eq = del /=/ "=" ++let sto_to_eol = store /([^ \t\n].*[^ \t\n]|[^ \t\n])/ + + (************************************************************************ +- * SIMPLE ENTRIES ++ * ENTRIES + *************************************************************************) + +-let entry_re = Rx.word - /(address|server)/ ++let entry_re = /[A-Za-z0-9._-]+/ + let entry = [ key entry_re . (sep_eq . sto_to_eol)? . eol ] + +-(************************************************************************ +- * STRUCTURED ENTRIES +- *************************************************************************) +- +-let address = [ key "address" . sep_eq . domains . sto_no_slash . eol ] +- +-let server = +- let port = [ Build.xchgs "#" "port" . store Rx.integer ] +- in let source = [ Build.xchgs "@" "source" . store /[^#\/ \t\n]+/ . port? ] +- in let srv_spec = store /(#|([^#@\/ \t\n]+))/ . port? . source? +- in [ key "server" . sep_eq . domains? . srv_spec? . eol ] +- + (************************************************************************ + * LENS + *************************************************************************) + +-let lns = (comment|empty|address|server|entry) * ++let lns = (comment|empty|entry) * + + let filter = incl "/etc/dnsmasq.conf" + . incl "/etc/dnsmasq.d/*" +diff --git a/lenses/tests/test_dnsmasq.aug b/lenses/tests/test_dnsmasq.aug +index c6a63d96..0abfa6bd 100644 +--- a/lenses/tests/test_dnsmasq.aug ++++ b/lenses/tests/test_dnsmasq.aug +@@ -6,16 +6,6 @@ let conf = "# Configuration file for dnsmasq. + + conf-dir=/etc/dnsmasq.d + selfmx +- +-address=/foo.com/bar.net/10.1.2.3 +- +-server=10.4.5.6#1234 +-server=/bar.com/foo.net/10.7.8.9 +-server=/foo.org/bar.org/10.3.2.1@eth0#5678 +-server=/baz.org/# +-server=/baz.net/#@eth1 +-server=10.6.5.4#1234@eth0#5678 +-server=/qux.com/qux.net/ + " + + test Dnsmasq.lns get conf = +@@ -25,40 +15,3 @@ test Dnsmasq.lns get conf = + {} + { "conf-dir" = "/etc/dnsmasq.d" } + { "selfmx" } +- {} +- { "address" = "10.1.2.3" +- { "domain" = "foo.com" } +- { "domain" = "bar.net" } +- } +- {} +- { "server" = "10.4.5.6" +- { "port" = "1234" } +- } +- { "server" = "10.7.8.9" +- { "domain" = "bar.com" } +- { "domain" = "foo.net" } +- } +- { "server" = "10.3.2.1" +- { "domain" = "foo.org" } +- { "domain" = "bar.org" } +- { "source" = "eth0" +- { "port" = "5678" } +- } +- } +- { "server" = "#" +- { "domain" = "baz.org" } +- } +- { "server" = "#" +- { "domain" = "baz.net" } +- { "source" = "eth1" } +- } +- { "server" = "10.6.5.4" +- { "port" = "1234" } +- { "source" = "eth0" +- { "port" = "5678" } +- } +- } +- { "server" +- { "domain" = "qux.com" } +- { "domain" = "qux.net" } +- } +-- +2.17.2 + diff --git a/SOURCES/0006-Sshd-revert-Sshd-module-to-1.1.0-compatible-add-Sshd.patch b/SOURCES/0006-Sshd-revert-Sshd-module-to-1.1.0-compatible-add-Sshd.patch new file mode 100644 index 0000000..d041f82 --- /dev/null +++ b/SOURCES/0006-Sshd-revert-Sshd-module-to-1.1.0-compatible-add-Sshd.patch @@ -0,0 +1,490 @@ +From 1c936bb38d39b238001364e1a7ee5479bdfff053 Mon Sep 17 00:00:00 2001 +From: Dominic Cleal +Date: Fri, 12 Jun 2015 11:01:57 +0100 +Subject: [PATCH] Sshd: revert Sshd module to 1.1.0-compatible, add Sshd_140 + +In order to keep the default sshd config lens compatible with 1.1.0, +the lens from 1.4.0 has been kept in the Sshd_140 module and is not +loaded by default. Use aug_transform, augtool --transform etc. to use +it instead of Sshd. +--- + lenses/sshd.aug | 52 +++++------- + lenses/sshd_140.aug | 141 +++++++++++++++++++++++++++++++++ + lenses/tests/test_sshd.aug | 56 ------------- + lenses/tests/test_sshd_140.aug | 136 +++++++++++++++++++++++++++++++ + tests/Makefile.am | 1 + + 5 files changed, 298 insertions(+), 88 deletions(-) + create mode 100644 lenses/sshd_140.aug + create mode 100644 lenses/tests/test_sshd_140.aug + +diff --git a/lenses/sshd.aug b/lenses/sshd.aug +index 55f6c4f7..785102ec 100644 +--- a/lenses/sshd.aug ++++ b/lenses/sshd.aug +@@ -70,55 +70,41 @@ module Sshd = + + let sep = Util.del_ws_spc + +- let indent = del /[ \t]*/ " " +- + let key_re = /[A-Za-z0-9]+/ +- - /MACs|Match|AcceptEnv|Subsystem|Ciphers|KexAlgorithms|(Allow|Deny)(Groups|Users)/i ++ - /MACs|Match|AcceptEnv|Subsystem|(Allow|Deny)(Groups|Users)/ + + let comment = Util.comment +- let comment_noindent = Util.comment_noindent + let empty = Util.empty + +- let array_entry (kw:regexp) (sq:string) = ++ let array_entry (k:string) = + let value = store /[^ \t\n]+/ in +- [ key kw . [ sep . seq sq . value]* . eol ] ++ [ key k . [ sep . seq k . value]* . eol ] + + let other_entry = + let value = store /[^ \t\n]+([ \t]+[^ \t\n]+)*/ in + [ key key_re . sep . value . eol ] + +- let accept_env = array_entry /AcceptEnv/i "AcceptEnv" ++ let accept_env = array_entry "AcceptEnv" + +- let allow_groups = array_entry /AllowGroups/i "AllowGroups" +- let allow_users = array_entry /AllowUsers/i "AllowUsers" +- let deny_groups = array_entry /DenyGroups/i "DenyGroups" +- let deny_users = array_entry /DenyUsers/i "DenyUsers" ++ let allow_groups = array_entry "AllowGroups" ++ let allow_users = array_entry "AllowUsers" ++ let deny_groups = array_entry "DenyGroups" ++ let deny_users = array_entry "DenyUsers" + + let subsystemvalue = + let value = store (/[^ \t\n](.*[^ \t\n])?/) in + [ key /[A-Za-z0-9\-]+/ . sep . value . eol ] + + let subsystem = +- [ key /Subsystem/i . sep . subsystemvalue ] ++ [ key "Subsystem" . sep . subsystemvalue ] + +- let list (kw:regexp) (sq:string) = +- let value = store /[^, \t\n]+/ in +- [ key kw . sep . +- [ seq sq . value ] . +- ([ seq sq . Util.del_str "," . value])* . ++ let macs = ++ let mac_value = store /[^, \t\n]+/ in ++ [ key "MACs" . sep . ++ [ seq "macs" . mac_value ] . ++ ([ seq "macs" . Util.del_str "," . mac_value])* . + eol ] + +- let macs = list /MACs/i "MACs" +- +- let ciphers = list /Ciphers/i "Ciphers" +- +- let kexalgorithms = list /KexAlgorithms/i "KexAlgorithms" +- +- let entry = accept_env | allow_groups | allow_users +- | deny_groups | subsystem | deny_users +- | macs | ciphers | kexalgorithms +- | other_entry +- + let condition_entry = + let value = store /[^ \t\n]+/ in + [ sep . key /[A-Za-z0-9]+/ . sep . value ] +@@ -126,15 +112,17 @@ module Sshd = + let match_cond = + [ label "Condition" . condition_entry+ . eol ] + +- let match_entry = indent . (entry | comment_noindent) +- | empty ++ let match_entry = ++ ( comment | empty | (Util.indent . other_entry) ) + + let match = +- [ key /Match/i . match_cond ++ [ key "Match" . match_cond + . [ label "Settings" . match_entry+ ] + ] + +- let lns = (entry | comment | empty)* . match* ++ let lns = (comment | empty | accept_env | allow_groups | allow_users ++ | deny_groups | subsystem | deny_users | macs ++ | other_entry ) * . match* + + let xfm = transform lns (incl "/etc/ssh/sshd_config") + +diff --git a/lenses/sshd_140.aug b/lenses/sshd_140.aug +new file mode 100644 +index 00000000..8a7f176f +--- /dev/null ++++ b/lenses/sshd_140.aug +@@ -0,0 +1,141 @@ ++(* ++Module: Sshd_140 ++ Parses /etc/ssh/sshd_config ++ ++ This module is compatible with Augeas 1.4.0, but is not loaded by default. ++ ++Author: David Lutterkort lutter@redhat.com ++ Dominique Dumont dominique.dumont@hp.com ++ ++About: Reference ++ sshd_config man page. ++ See http://www.openbsd.org/cgi-bin/man.cgi?query=sshd_config&sektion=5 ++ ++About: License ++ This file is licensed under the LGPL v2+. ++ ++About: Lens Usage ++ Sample usage of this lens in augtool: ++ ++ * Get your current setup ++ > print /files/etc/ssh/sshd_config ++ ... ++ ++ * Set X11Forwarding to "no" ++ > set /files/etc/ssh/sshd_config/X11Forwarding "no" ++ ++ More advanced usage: ++ ++ * Set a Match section ++ > set /files/etc/ssh/sshd_config/Match[1]/Condition/User "foo" ++ > set /files/etc/ssh/sshd_config/Match[1]/Settings/X11Forwarding "yes" ++ ++ Saving your file: ++ ++ > save ++ ++ ++About: CAVEATS ++ ++ In sshd_config, Match blocks must be located at the end of the file. ++ This means that any new "global" parameters (i.e. outside of a Match ++ block) must be written before the first Match block. By default, ++ Augeas will write new parameters at the end of the file. ++ ++ I.e. if you have a Match section and no ChrootDirectory parameter, ++ this command: ++ ++ > set /files/etc/ssh/sshd_config/ChrootDirectory "foo" ++ ++ will be stored in a new node after the Match section and Augeas will ++ refuse to save sshd_config file. ++ ++ To create a new parameter as the right place, you must first create ++ a new Augeas node before the Match section: ++ ++ > ins ChrootDirectory before /files/etc/ssh/sshd_config/Match ++ ++ Then, you can set the parameter ++ ++ > set /files/etc/ssh/sshd_config/ChrootDirectory "foo" ++ ++ ++About: Configuration files ++ This lens applies to /etc/ssh/sshd_config ++ ++*) ++ ++module Sshd_140 = ++ let eol = del /[ \t]*\n/ "\n" ++ ++ let sep = Util.del_ws_spc ++ ++ let indent = del /[ \t]*/ " " ++ ++ let key_re = /[A-Za-z0-9]+/ ++ - /MACs|Match|AcceptEnv|Subsystem|Ciphers|KexAlgorithms|(Allow|Deny)(Groups|Users)/i ++ ++ let comment = Util.comment ++ let comment_noindent = Util.comment_noindent ++ let empty = Util.empty ++ ++ let array_entry (kw:regexp) (sq:string) = ++ let value = store /[^ \t\n]+/ in ++ [ key kw . [ sep . seq sq . value]* . eol ] ++ ++ let other_entry = ++ let value = store /[^ \t\n]+([ \t]+[^ \t\n]+)*/ in ++ [ key key_re . sep . value . eol ] ++ ++ let accept_env = array_entry /AcceptEnv/i "AcceptEnv" ++ ++ let allow_groups = array_entry /AllowGroups/i "AllowGroups" ++ let allow_users = array_entry /AllowUsers/i "AllowUsers" ++ let deny_groups = array_entry /DenyGroups/i "DenyGroups" ++ let deny_users = array_entry /DenyUsers/i "DenyUsers" ++ ++ let subsystemvalue = ++ let value = store (/[^ \t\n](.*[^ \t\n])?/) in ++ [ key /[A-Za-z0-9\-]+/ . sep . value . eol ] ++ ++ let subsystem = ++ [ key /Subsystem/i . sep . subsystemvalue ] ++ ++ let list (kw:regexp) (sq:string) = ++ let value = store /[^, \t\n]+/ in ++ [ key kw . sep . ++ [ seq sq . value ] . ++ ([ seq sq . Util.del_str "," . value])* . ++ eol ] ++ ++ let macs = list /MACs/i "MACs" ++ ++ let ciphers = list /Ciphers/i "Ciphers" ++ ++ let kexalgorithms = list /KexAlgorithms/i "KexAlgorithms" ++ ++ let entry = accept_env | allow_groups | allow_users ++ | deny_groups | subsystem | deny_users ++ | macs | ciphers | kexalgorithms ++ | other_entry ++ ++ let condition_entry = ++ let value = store /[^ \t\n]+/ in ++ [ sep . key /[A-Za-z0-9]+/ . sep . value ] ++ ++ let match_cond = ++ [ label "Condition" . condition_entry+ . eol ] ++ ++ let match_entry = indent . (entry | comment_noindent) ++ | empty ++ ++ let match = ++ [ key /Match/i . match_cond ++ . [ label "Settings" . match_entry+ ] ++ ] ++ ++ let lns = (entry | comment | empty)* . match* ++ ++(* Local Variables: *) ++(* mode: caml *) ++(* End: *) +diff --git a/lenses/tests/test_sshd.aug b/lenses/tests/test_sshd.aug +index 5954e16f..788a12f0 100644 +--- a/lenses/tests/test_sshd.aug ++++ b/lenses/tests/test_sshd.aug +@@ -1,4 +1,3 @@ +-(* Module: Test_sshd *) + module Test_sshd = + + let accept_env = "Protocol 2 +@@ -75,61 +74,6 @@ Match User sarko Group pres.* + Match User bush Group pres.* Host white.house.* + Banner /etc/welcome.txt\n" + +-(* Test: Sshd.lns +- Indent when adding to a Match group *) +- test Sshd.lns put match_blocks after +- set "Match[1]/Settings/PermitRootLogin" "yes"; +- set "Match[1]/Settings/#comment" "a comment" = +-"X11Forwarding yes +-Match User sarko Group pres.* +- Banner /etc/bienvenue.txt +- X11Forwarding no +- PermitRootLogin yes +- # a comment +-Match User bush Group pres.* Host white.house.* +-Banner /etc/welcome.txt\n" +- +- +-(* Test: Sshd.lns +- Parse Ciphers and KexAlgorithms as lists (GH issue #69) *) +-test Sshd.lns get "Ciphers aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes128-ctr +-KexAlgorithms diffie-hellman-group-exchange-sha256,diffie-hellman-group14-sha1,diffie-hellman-group-exchange-sha1\n" = +- { "Ciphers" +- { "1" = "aes256-gcm@openssh.com" } +- { "2" = "aes128-gcm@openssh.com" } +- { "3" = "aes256-ctr" } +- { "4" = "aes128-ctr" } +- } +- { "KexAlgorithms" +- { "1" = "diffie-hellman-group-exchange-sha256" } +- { "2" = "diffie-hellman-group14-sha1" } +- { "3" = "diffie-hellman-group-exchange-sha1" } +- } +- +-(* Test: Sshd.lns +- Keys are case-insensitive *) +-test Sshd.lns get "ciPheRs aes256-gcm@openssh.com,aes128-ctr +-maTcH User foo +- x11forwarding no\n" = +- { "ciPheRs" +- { "1" = "aes256-gcm@openssh.com" } +- { "2" = "aes128-ctr" } +- } +- { "maTcH" +- { "Condition" +- { "User" = "foo" } +- } +- { "Settings" +- { "x11forwarding" = "no" } +- } +- } +- +-(* Test: Sshd.lns +- Allow AllowGroups in Match groups (GH issue #75) *) +-test Sshd.lns get "Match User foo +-AllowGroups users\n" = +- { "Match" { "Condition" { "User" = "foo" } } +- { "Settings" { "AllowGroups" { "1" = "users" } } } } + + (* Local Variables: *) + (* mode: caml *) +diff --git a/lenses/tests/test_sshd_140.aug b/lenses/tests/test_sshd_140.aug +new file mode 100644 +index 00000000..056c53f9 +--- /dev/null ++++ b/lenses/tests/test_sshd_140.aug +@@ -0,0 +1,136 @@ ++(* Module: Test_sshd_140 *) ++module Test_sshd_140 = ++ ++ let accept_env = "Protocol 2 ++AcceptEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT ++AcceptEnv LC_IDENTIFICATION LC_ALL\n" ++ ++ test Sshd_140.lns get accept_env = ++ { "Protocol" = "2" } ++ { "AcceptEnv" ++ { "1" = "LC_PAPER" } ++ { "2" = "LC_NAME" } ++ { "3" = "LC_ADDRESS" } ++ { "4" = "LC_TELEPHONE" } ++ { "5" = "LC_MEASUREMENT" } } ++ { "AcceptEnv" ++ { "6" = "LC_IDENTIFICATION" } ++ { "7" = "LC_ALL" } } ++ ++ ++ test Sshd_140.lns get "HostKey /etc/ssh/ssh_host_rsa_key ++HostKey /etc/ssh/ssh_host_dsa_key\n" = ++ { "HostKey" = "/etc/ssh/ssh_host_rsa_key" } ++ { "HostKey" = "/etc/ssh/ssh_host_dsa_key" } ++ ++ ++ test Sshd_140.lns put accept_env after ++ rm "AcceptEnv"; ++ rm "AcceptEnv"; ++ set "Protocol" "1.5"; ++ set "X11Forwarding" "yes" ++ = "Protocol 1.5\nX11Forwarding yes\n" ++ ++ test Sshd_140.lns get "AuthorizedKeysFile %h/.ssh/authorized_keys\n" = ++ { "AuthorizedKeysFile" = "%h/.ssh/authorized_keys" } ++ ++ test Sshd_140.lns get "Subsystem sftp /usr/lib/openssh/sftp-server\n" = ++ { "Subsystem" ++ { "sftp" = "/usr/lib/openssh/sftp-server" } } ++ ++ test Sshd_140.lns get "Subsystem sftp-test /usr/lib/openssh/sftp-server\n" = ++ { "Subsystem" ++ { "sftp-test" = "/usr/lib/openssh/sftp-server" } } ++ ++ ++ ++ let match_blocks = "X11Forwarding yes ++Match User sarko Group pres.* ++ Banner /etc/bienvenue.txt ++ X11Forwarding no ++Match User bush Group pres.* Host white.house.* ++Banner /etc/welcome.txt ++" ++ test Sshd_140.lns get match_blocks = ++ { "X11Forwarding" = "yes"} ++ { "Match" ++ { "Condition" { "User" = "sarko" } ++ { "Group" = "pres.*" } } ++ { "Settings" { "Banner" = "/etc/bienvenue.txt" } ++ { "X11Forwarding" = "no" } } } ++ { "Match" ++ { "Condition" { "User" = "bush" } ++ { "Group" = "pres.*" } ++ { "Host" = "white.house.*" } } ++ { "Settings" { "Banner" = "/etc/welcome.txt" } } } ++ ++ test Sshd_140.lns put match_blocks after ++ insb "Subsystem" "/Match[1]"; ++ set "/Subsystem/sftp" "/usr/libexec/openssh/sftp-server" ++ = "X11Forwarding yes ++Subsystem sftp /usr/libexec/openssh/sftp-server ++Match User sarko Group pres.* ++ Banner /etc/bienvenue.txt ++ X11Forwarding no ++Match User bush Group pres.* Host white.house.* ++Banner /etc/welcome.txt\n" ++ ++(* Test: Sshd_140.lns ++ Indent when adding to a Match group *) ++ test Sshd_140.lns put match_blocks after ++ set "Match[1]/Settings/PermitRootLogin" "yes"; ++ set "Match[1]/Settings/#comment" "a comment" = ++"X11Forwarding yes ++Match User sarko Group pres.* ++ Banner /etc/bienvenue.txt ++ X11Forwarding no ++ PermitRootLogin yes ++ # a comment ++Match User bush Group pres.* Host white.house.* ++Banner /etc/welcome.txt\n" ++ ++ ++(* Test: Sshd_140.lns ++ Parse Ciphers and KexAlgorithms as lists (GH issue #69) *) ++test Sshd_140.lns get "Ciphers aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes128-ctr ++KexAlgorithms diffie-hellman-group-exchange-sha256,diffie-hellman-group14-sha1,diffie-hellman-group-exchange-sha1\n" = ++ { "Ciphers" ++ { "1" = "aes256-gcm@openssh.com" } ++ { "2" = "aes128-gcm@openssh.com" } ++ { "3" = "aes256-ctr" } ++ { "4" = "aes128-ctr" } ++ } ++ { "KexAlgorithms" ++ { "1" = "diffie-hellman-group-exchange-sha256" } ++ { "2" = "diffie-hellman-group14-sha1" } ++ { "3" = "diffie-hellman-group-exchange-sha1" } ++ } ++ ++(* Test: Sshd_140.lns ++ Keys are case-insensitive *) ++test Sshd_140.lns get "ciPheRs aes256-gcm@openssh.com,aes128-ctr ++maTcH User foo ++ x11forwarding no\n" = ++ { "ciPheRs" ++ { "1" = "aes256-gcm@openssh.com" } ++ { "2" = "aes128-ctr" } ++ } ++ { "maTcH" ++ { "Condition" ++ { "User" = "foo" } ++ } ++ { "Settings" ++ { "x11forwarding" = "no" } ++ } ++ } ++ ++(* Test: Sshd_140.lns ++ Allow AllowGroups in Match groups (GH issue #75) *) ++test Sshd_140.lns get "Match User foo ++AllowGroups users\n" = ++ { "Match" { "Condition" { "User" = "foo" } } ++ { "Settings" { "AllowGroups" { "1" = "users" } } } } ++ ++(* Local Variables: *) ++(* mode: caml *) ++(* End: *) +diff --git a/tests/Makefile.am b/tests/Makefile.am +index b4563540..387ac7d2 100644 +--- a/tests/Makefile.am ++++ b/tests/Makefile.am +@@ -189,6 +189,7 @@ lens_tests = \ + lens-squid.sh \ + lens-ssh.sh \ + lens-sshd.sh \ ++ lens-sshd_140.sh \ + lens-sssd.sh \ + lens-stunnel.sh \ + lens-subversion.sh \ +-- +2.17.2 + diff --git a/SOURCES/0007-Dhcpd-revert-Dhcpd-module-to-1.1.0-compatible-add-Dh.patch b/SOURCES/0007-Dhcpd-revert-Dhcpd-module-to-1.1.0-compatible-add-Dh.patch new file mode 100644 index 0000000..f9270c3 --- /dev/null +++ b/SOURCES/0007-Dhcpd-revert-Dhcpd-module-to-1.1.0-compatible-add-Dh.patch @@ -0,0 +1,1750 @@ +From c93dc5ca4c87f38772c98e3134ddc6662a98bc02 Mon Sep 17 00:00:00 2001 +From: Dominic Cleal +Date: Fri, 12 Jun 2015 11:09:09 +0100 +Subject: [PATCH] Dhcpd: revert Dhcpd module to 1.1.0-compatible, add Dhcpd_140 + +In order to keep the default sshd config lens compatible with 1.1.0, +the lens from 1.4.0 has been kept in the Dhcpd_140 module and is not +loaded by default. Use aug_transform, augtool --transform etc. to use +it instead of Dhcpd. +--- + lenses/dhcpd.aug | 182 ++-------- + lenses/dhcpd_140.aug | 512 +++++++++++++++++++++++++++ + lenses/tests/test_dhcpd.aug | 214 +---------- + lenses/tests/test_dhcpd_140.aug | 606 ++++++++++++++++++++++++++++++++ + tests/Makefile.am | 1 + + 5 files changed, 1152 insertions(+), 363 deletions(-) + create mode 100644 lenses/dhcpd_140.aug + create mode 100644 lenses/tests/test_dhcpd_140.aug + +diff --git a/lenses/dhcpd.aug b/lenses/dhcpd.aug +index f84a409c..21a5ce60 100644 +--- a/lenses/dhcpd.aug ++++ b/lenses/dhcpd.aug +@@ -65,12 +65,12 @@ let eos = comment? + let sep_spc = del /[ \t]+/ " " + let sep_osp = del /[ \t]*/ "" + let sep_scl = del /[ \t]*;([ \t]*\n)*/ ";\n" +-let sep_obr = del /[ \t\n]*\{([ \t]*\n)*/ " {\n" ++let sep_obr = del /[ \t]*\{([ \t]*\n)*/ " {\n" + let sep_cbr = del /[ \t]*\}([ \t]*\n)*/ "}\n" + let sep_com = del /[ \t\n]*,[ \t\n]*/ ", " + let sep_slh = del "\/" "/" + let sep_col = del ":" ":" +-let sep_eq = del /[ \t\n]*=[ \t\n]*/ "=" ++let sep_eq = del /[ \t]*=[ \t]*/ "=" + let scl = del ";" ";" + + (* Define basic types *) +@@ -94,11 +94,6 @@ let ip = Rx.ipv4 + let bare = del qchar? "" . store (bchar+) . del qchar? "" + let quote = Quote.do_quote (store (bchar* . /[ \t'\/]/ . bchar*)+) + let dquote = Quote.do_dquote (store (bchar+)) +- (* these two are for special cases. bare_to_scl is for any bareword that is +- * space or semicolon terminated. dquote_any allows almost any character in +- * between the quotes. *) +- let bare_to_scl = Quote.do_dquote_opt (store /[^" \t\n;]+/) +- let dquote_any = Quote.do_dquote (store /[^"\n]*[ \t]+[^"\n]*/) + + let sto_to_spc = store /[^\\#,;\{\}" \t\n]+|"[^\\#"\n]+"/ + let sto_to_scl = store /[^ \t;][^;\n=]+[^ \t;]|[^ \t;=]+/ +@@ -197,7 +192,6 @@ let stmt_string_re = "ddns-update-style" + | "use-lease-addr-for-default-route" + | "vendor-option-space" + | "primary" +- | "omapi-key" + + let stmt_string_tpl (kw:regexp) (l:lens) = [ indent + . key kw +@@ -230,51 +224,26 @@ let stmt_range = [ indent + let stmt_hardware = [ indent + . key "hardware" + . sep_spc +- . [ label "type" . store /ethernet|tokenring|fddi/ ] ++ . [ label "type" . store /ethernet|tokenring/ ] + . sep_spc + . [ label "address" . store /[a-fA-F0-9:-]+/ ] + . sep_scl + . eos ] + +-(************************************************************************ +- * SET STATEMENTS +- *************************************************************************) +-let stmt_set = [ indent +- . key "set" +- . sep_spc +- . store word +- . sep_spc +- . Sep.equal +- . sep_spc +- . [ label "value" . sto_to_scl ] +- . sep_scl +- . eos ] +- + (************************************************************************ + * OPTION STATEMENTS + *************************************************************************) + (* The general case is considering options as a list *) + ++let stmt_option_code = [ label "label" . store word . sep_spc ] ++ . [ key "code" . sep_spc . store word ] ++ . sep_eq ++ . [ label "type" . store word ] + +-let stmt_option_value = /((array of[ \t]+)?(((un)?signed[ \t]+)?integer (8|16|32)|string|ip6?-address|boolean|domain-list|text)|encapsulate [A-Za-z0-9_.-]+)/ + + let stmt_option_list = ([ label "arg" . bare ] | [ label "arg" . quote ]) + . ( sep_com . ([ label "arg" . bare ] | [ label "arg" . quote ]))* + +-let del_trail_spc = del /[ \t\n]*/ "" +- +-let stmt_record = counter "record" . Util.del_str "{" +- . sep_spc +- . ([seq "record" . store stmt_option_value . sep_com]* +- . [seq "record" . store stmt_option_value . del_trail_spc])? +- . Util.del_str "}" +- +-let stmt_option_code = [ label "label" . store word . sep_spc ] +- . [ key "code" . sep_spc . store word ] +- . sep_eq +- . ([ label "type" . store stmt_option_value ] +- |[ label "record" . stmt_record ]) +- + let stmt_option_basic = [ key word . sep_spc . stmt_option_list ] + let stmt_option_extra = [ key word . sep_spc . store /true|false/ . sep_spc . stmt_option_list ] + +@@ -302,13 +271,10 @@ let stmt_option = stmt_option1 | stmt_option2 + (* this statement is not well documented in the manual dhcpd.conf + we support basic use case *) + +-let stmt_subclass = [ indent . key "subclass" . sep_spc +- . ( [ label "name" . bare_to_scl ]|[ label "name" . dquote_any ] ) +- . sep_spc +- . ( [ label "value" . bare_to_scl ]|[ label "value" . dquote_any ] ) +- . sep_scl +- . eos ] +- ++let stmt_subclass = [ indent . key "subclass" . sep_spc . ++ ([ label "name" . quote ]| ++ [ label "name" . bare ]) . sep_spc . ++ [ label "value" . bare ] . sep_scl . eos ] + + (************************************************************************ + * ALLOW/DENY STATEMENTS +@@ -316,18 +282,10 @@ let stmt_subclass = [ indent . key "subclass" . sep_spc + (* We have to use special key for allow/deny members of + to avoid ambiguity in the put direction *) + +-let allow_deny_re = /unknown(-|[ ]+)clients/ +- | /known(-|[ ]+)clients/ +- | /all[ ]+clients/ ++let allow_deny_re = "unknown-clients" + | /dynamic[ ]+bootp[ ]+clients/ + | /authenticated[ ]+clients/ + | /unauthenticated[ ]+clients/ +- | "bootp" +- | "booting" +- | "duplicates" +- | "declines" +- | "client-updates" +- | "leasequery" + + let stmt_secu_re = "allow" + | "deny" +@@ -335,17 +293,9 @@ let stmt_secu_re = "allow" + let del_allow = del /allow[ ]+members[ ]+of/ "allow members of" + let del_deny = del /deny[ \t]+members[ \t]+of/ "deny members of" + +-(* bare is anything but whitespace, quote marks or semicolon. +- * technically this should be locked down to mostly alphanumerics, but the +- * idea right now is just to make things work. Also ideally I would use +- * dquote_space but I had a whale of a time with it. It doesn't like +- * semicolon termination and my attempts to fix that led me to 3 hours of +- * frustration and back to this :) +- *) + let stmt_secu_tpl (l:lens) (s:string) = +- [ indent . l . sep_spc . label s . bare_to_scl . sep_scl . eos ] | +- [ indent . l . sep_spc . label s . dquote_any . sep_scl . eos ] +- ++ [ indent . l . sep_spc . label s . bare . sep_scl . eos ] | ++ [ indent . l . sep_spc . label s . quote . sep_scl . eos ] + + let stmt_secu = [ indent . key stmt_secu_re . sep_spc . + store allow_deny_re . sep_scl . eos ] | +@@ -356,62 +306,17 @@ let stmt_secu = [ indent . key stmt_secu_re . sep_spc . + * MATCH STATEMENTS + *************************************************************************) + ++let sto_fct = store (word . /[ \t]*\([^)]*\)/) ++let sto_option = store (/option[ ]+/ . word) + let sto_com = /[^ \t\n,\(\)][^,\(\)]*[^ \t\n,\(\)]|[^ \t\n,\(\)]+/ | word . /[ \t]*\([^)]*\)/ +-(* this is already the most complicated part of this module and it's about to +- * get worse. match statements can be way more complicated than this +- * +- * examples: +- * using or: +- * match if ((option vendor-class-identifier="Banana Bready") or (option vendor-class-identifier="Cherry Sunfire")); +- * unneeded parenthesis: +- * match if (option vendor-class-identifier="Hello"); +- * +- * and of course the fact that the above two rules used one of infinately +- * many potential options instead of a builtin function. +- *) +-(* sto_com doesn't support quoted strings as arguments. It also doesn't +- support single arguments (needs to match a comma) It will need to be +- updated for lcase, ucase and log to be workable. +- +- it also doesn't support no arguments, so gethostbyname() doesn't work. +- +- option and config-option are considered operators. They should be matched +- in stmt_entry but also available under "match if" and "if" conditionals +- leased-address, host-decl-name, both take no args and return a value. We +- might need to treat them as variable names in the parser. +- +- things like this may be near-impossible to parse even with recursion +- because we have no way of knowing when or if a subfunction takes arguments +- set ClientMac = binary-to-ascii(16, 8, ":", substring(hardware, 1, 6)); +- +- even if we could parse it, they could get arbitrarily complicated like: +- binary-to-ascii(16, 8, ":", substring(hardware, 1, 6) and substring(hardware, 2, 3)); +- +- so at some point we may need to programmatically knock it off and tell +- people to put weird stuff in an include file that augeas doesn't parse. +- +- the other option is to change the API to not parse the if statement at all, +- just pull in the conditional as a string. +- *) +- +-let fct_re = "substring" | "binary-to-ascii" | "suffix" | "lcase" | "ucase" +- | "gethostbyname" | "packet" +- | "concat" | "reverse" | "encode-int" +- | "extract-int" | "lease-time" | "client-state" | "exists" | "known" | "static" +- | "pick-first-value" | "log" | "execute" +- +-(* not needs to be different because it's a negation of whatever happens next *) +-let op_re = "~="|"="|"~~"|"and"|"or" ++let fct_re = "substring" | "binary-to-ascii" + + let fct_args = [ label "args" . dels "(" . sep_osp . + ([ label "arg" . store sto_com ] . [ label "arg" . sep_com . store sto_com ]+) . + sep_osp . dels ")" ] + +-let stmt_match_ifopt = [ dels "if" . sep_spc . key "option" . sep_spc . store word . +- sep_eq . ([ label "value" . bare_to_scl ]|[ label "value" . dquote_any ]) ] +- +-let stmt_match_func = [ store fct_re . sep_osp . label "function" . fct_args ] . +- sep_eq . ([ label "value" . bare_to_scl ]|[ label "value" . dquote_any ]) ++let stmt_match_if = [ dels "if" . sep_spc . store fct_re . sep_osp . label "function" . fct_args ] . ++ sep_eq . ([ label "value" . bare ]|[ label "value" . quote ]) + + let stmt_match_pfv = [ label "function" . store "pick-first-value" . sep_spc . + dels "(" . sep_osp . +@@ -422,7 +327,7 @@ let stmt_match_pfv = [ label "function" . store "pick-first-value" . sep_spc . + + let stmt_match_tpl (l:lens) = [ indent . key "match" . sep_spc . l . sep_scl . eos ] + +-let stmt_match = stmt_match_tpl (dels "if" . sep_spc . stmt_match_func | stmt_match_pfv | stmt_match_ifopt) ++let stmt_match = stmt_match_tpl (stmt_match_if | stmt_match_pfv ) + + (************************************************************************ + * BLOCK STATEMENTS +@@ -438,11 +343,12 @@ let stmt_entry = stmt_secu + | stmt_noarg + | stmt_match + | stmt_subclass +- | stmt_set + | empty + | comment + +-let stmt_block_noarg_re = "pool" | "group" ++let stmt_block_noarg_re = "pool" ++ | "group" ++ | "allow-update" + + let stmt_block_noarg (body:lens) + = [ indent +@@ -456,14 +362,16 @@ let stmt_block_arg_re = "host" + | "shared-network" + | /failover[ ]+peer/ + | "zone" +- | "group" +- | "on" ++ | "key" + + let stmt_block_arg (body:lens) +- = ([ indent . key stmt_block_arg_re . sep_spc . dquote_any . sep_obr . body* . sep_cbr ] +- |[ indent . key stmt_block_arg_re . sep_spc . bare_to_scl . sep_obr . body* . sep_cbr ] +- |[ indent . del /key/ "key" . label "key_block" . sep_spc . dquote_any . sep_obr . body* . sep_cbr . del /(;([ \t]*\n)*)?/ "" ] +- |[ indent . del /key/ "key" . label "key_block" . sep_spc . bare_to_scl . sep_obr . body* . sep_cbr . del /(;([ \t]*\n)*)?/ "" ]) ++ = [ indent ++ . key stmt_block_arg_re ++ . sep_spc ++ . sto_to_spc ++ . sep_obr ++ . body* ++ . sep_cbr ] + + let stmt_block_subnet (body:lens) + = [ indent +@@ -476,37 +384,11 @@ let stmt_block_subnet (body:lens) + . body* + . sep_cbr ] + +-let conditional (body:lens) = +- let condition = /[^{ \r\t\n][^{\n]*[^{ \r\t\n]|[^{ \t\n\r]/ +- in let elsif = [ indent +- . Build.xchgs "elsif" "@elsif" +- . sep_spc +- . store condition +- . sep_obr +- . body* +- . sep_cbr ] +- in let else = [ indent +- . Build.xchgs "else" "@else" +- . sep_obr +- . body* +- . sep_cbr ] +- in [ indent +- . Build.xchgs "if" "@if" +- . sep_spc +- . store condition +- . sep_obr +- . body* +- . sep_cbr +- . elsif* +- . else? ] +- +- + let all_block (body:lens) = + let lns1 = stmt_block_subnet body in + let lns2 = stmt_block_arg body in + let lns3 = stmt_block_noarg body in +- let lns4 = conditional body in +- (lns1 | lns2 | lns3 | lns4 | stmt_entry) ++ (lns1 | lns2 | lns3 | stmt_entry) + + let rec lns_staging = stmt_entry|all_block lns_staging + let lns = (lns_staging)* +diff --git a/lenses/dhcpd_140.aug b/lenses/dhcpd_140.aug +new file mode 100644 +index 00000000..c9072990 +--- /dev/null ++++ b/lenses/dhcpd_140.aug +@@ -0,0 +1,512 @@ ++(* ++Module: Dhcpd_140 ++ BIND dhcp 3 server configuration module for Augeas ++ ++ This module is compatible with Augeas 1.4.0, but is not loaded by default. ++ ++Author: Francis Giraldeau ++ ++About: Reference ++ Reference: manual of dhcpd.conf and dhcp-eval ++ Follow dhclient module for tree structure ++ ++About: License ++ This file is licensed under the GPL. ++ ++About: Lens Usage ++ Sample usage of this lens in augtool ++ ++ Directive without argument. ++ Set this dhcpd server authoritative on the domain. ++ > clear /files/etc/dhcp3/dhcpd.conf/authoritative ++ ++ Directives with integer or string argument. ++ Set max-lease-time to one hour: ++ > set /files/etc/dhcp3/dhcpd.conf/max-lease-time 3600 ++ ++ Options are declared as a list, even for single values. ++ Set the domain of the network: ++ > set /files/etc/dhcp3/dhcpd.conf/option/domain-name/arg example.org ++ Set two name server: ++ > set /files/etc/dhcp3/dhcpd.conf/option/domain-name-servers/arg[1] foo.example.org ++ > set /files/etc/dhcp3/dhcpd.conf/option/domain-name-servers/arg[2] bar.example.org ++ ++ Create the subnet 172.16.0.1 with 10 addresses: ++ > clear /files/etc/dhcp3/dhcpd.conf/subnet[last() + 1] ++ > set /files/etc/dhcp3/dhcpd.conf/subnet[last()]/network 172.16.0.0 ++ > set /files/etc/dhcp3/dhcpd.conf/subnet[last()]/netmask 255.255.255.0 ++ > set /files/etc/dhcp3/dhcpd.conf/subnet[last()]/range/from 172.16.0.10 ++ > set /files/etc/dhcp3/dhcpd.conf/subnet[last()]/range/to 172.16.0.20 ++ ++ Create a new group "foo" with one static host. Nodes type and address are ordered. ++ > ins group after /files/etc/dhcp3/dhcpd.conf/subnet[network='172.16.0.0']/*[last()] ++ > set /files/etc/dhcp3/dhcpd.conf/subnet[network='172.16.0.0']/group[last()]/host foo ++ > set /files/etc/dhcp3/dhcpd.conf/subnet[network='172.16.0.0']/group[host='foo']/host/hardware/type "ethernet" ++ > set /files/etc/dhcp3/dhcpd.conf/subnet[network='172.16.0.0']/group[host='foo']/host/hardware/address "00:00:00:aa:bb:cc" ++ > set /files/etc/dhcp3/dhcpd.conf/subnet[network='172.16.0.0']/group[host='foo']/host/fixed-address 172.16.0.100 ++ ++About: Configuration files ++ This lens applies to /etc/dhcpd3/dhcpd.conf. See . ++*) ++ ++module Dhcpd_140 = ++ ++(************************************************************************ ++ * USEFUL PRIMITIVES ++ *************************************************************************) ++let dels (s:string) = del s s ++let eol = Util.eol ++let comment = Util.comment ++let empty = Util.empty ++let indent = Util.indent ++let eos = comment? ++ ++(* Define separators *) ++let sep_spc = del /[ \t]+/ " " ++let sep_osp = del /[ \t]*/ "" ++let sep_scl = del /[ \t]*;([ \t]*\n)*/ ";\n" ++let sep_obr = del /[ \t\n]*\{([ \t]*\n)*/ " {\n" ++let sep_cbr = del /[ \t]*\}([ \t]*\n)*/ "}\n" ++let sep_com = del /[ \t\n]*,[ \t\n]*/ ", " ++let sep_slh = del "\/" "/" ++let sep_col = del ":" ":" ++let sep_eq = del /[ \t\n]*=[ \t\n]*/ "=" ++let scl = del ";" ";" ++ ++(* Define basic types *) ++let word = /[A-Za-z0-9_.-]+(\[[0-9]+\])?/ ++let ip = Rx.ipv4 ++ ++(* Define fields *) ++ ++(* adapted from sysconfig.aug *) ++ (* Chars allowed in a bare string *) ++ let bchar = /[^ \t\n"'\\{}#,()\/]|\\\\./ ++ let qchar = /["']/ (* " *) ++ ++ (* We split the handling of right hand sides into a few cases: ++ * bare - strings that contain no spaces, optionally enclosed in ++ * single or double quotes ++ * dquot - strings that contain at least one space, apostrophe or slash ++ * which must be enclosed in double quotes ++ * squot - strings that contain an unescaped double quote ++ *) ++ let bare = del qchar? "" . store (bchar+) . del qchar? "" ++ let quote = Quote.do_quote (store (bchar* . /[ \t'\/]/ . bchar*)+) ++ let dquote = Quote.do_dquote (store (bchar+)) ++ (* these two are for special cases. bare_to_scl is for any bareword that is ++ * space or semicolon terminated. dquote_any allows almost any character in ++ * between the quotes. *) ++ let bare_to_scl = Quote.do_dquote_opt (store /[^" \t\n;]+/) ++ let dquote_any = Quote.do_dquote (store /[^"\n]*[ \t]+[^"\n]*/) ++ ++let sto_to_spc = store /[^\\#,;\{\}" \t\n]+|"[^\\#"\n]+"/ ++let sto_to_scl = store /[^ \t;][^;\n=]+[^ \t;]|[^ \t;=]+/ ++ ++let sto_number = store /[0-9][0-9]*/ ++ ++(************************************************************************ ++ * NO ARG STATEMENTS ++ *************************************************************************) ++ ++let stmt_noarg_re = "authoritative" ++ | "primary" ++ | "secondary" ++ ++let stmt_noarg = [ indent ++ . key stmt_noarg_re ++ . sep_scl ++ . eos ] ++ ++(************************************************************************ ++ * INT ARG STATEMENTS ++ *************************************************************************) ++ ++let stmt_integer_re = "default-lease-time" ++ | "max-lease-time" ++ | "min-lease-time" ++ | /lease[ ]+limit/ ++ | "port" ++ | /peer[ ]+port/ ++ | "max-response-delay" ++ | "max-unacked-updates" ++ | "mclt" ++ | "split" ++ | /load[ ]+balance[ ]+max[ ]+seconds/ ++ | "max-lease-misbalance" ++ | "max-lease-ownership" ++ | "min-balance" ++ | "max-balance" ++ | "adaptive-lease-time-threshold" ++ | "dynamic-bootp-lease-length" ++ | "local-port" ++ | "min-sec" ++ | "omapi-port" ++ | "ping-timeout" ++ | "remote-port" ++ ++let stmt_integer = [ indent ++ . key stmt_integer_re ++ . sep_spc ++ . sto_number ++ . sep_scl ++ . eos ] ++ ++(************************************************************************ ++ * STRING ARG STATEMENTS ++ *************************************************************************) ++ ++let stmt_string_re = "ddns-update-style" ++ | "ddns-updates" ++ | "ddns-hostname" ++ | "ddns-domainname" ++ | "ddns-rev-domainname" ++ | "log-facility" ++ | "server-name" ++ | "fixed-address" ++ | /failover[ ]+peer/ ++ | "use-host-decl-names" ++ | "next-server" ++ | "address" ++ | /peer[ ]+address/ ++ | "type" ++ | "file" ++ | "algorithm" ++ | "secret" ++ | "key" ++ | "include" ++ | "hba" ++ | "boot-unknown-clients" ++ | "db-time-format" ++ | "do-forward-updates" ++ | "dynamic-bootp-lease-cutoff" ++ | "get-lease-hostnames" ++ | "infinite-is-reserved" ++ | "lease-file-name" ++ | "local-address" ++ | "one-lease-per-client" ++ | "pid-file-name" ++ | "ping-check" ++ | "server-identifier" ++ | "site-option-space" ++ | "stash-agent-options" ++ | "update-conflict-detection" ++ | "update-optimization" ++ | "update-static-leases" ++ | "use-host-decl-names" ++ | "use-lease-addr-for-default-route" ++ | "vendor-option-space" ++ | "primary" ++ | "omapi-key" ++ ++let stmt_string_tpl (kw:regexp) (l:lens) = [ indent ++ . key kw ++ . sep_spc ++ . l ++ . sep_scl ++ . eos ] ++ ++let stmt_string = stmt_string_tpl stmt_string_re bare ++ | stmt_string_tpl stmt_string_re quote ++ | stmt_string_tpl "filename" dquote ++ ++(************************************************************************ ++ * RANGE STATEMENTS ++ *************************************************************************) ++ ++let stmt_range = [ indent ++ . key "range" ++ . sep_spc ++ . [ label "flag" . store /dynamic-bootp/ . sep_spc ]? ++ . [ label "from" . store ip . sep_spc ]? ++ . [ label "to" . store ip ] ++ . sep_scl ++ . eos ] ++ ++(************************************************************************ ++ * HARDWARE STATEMENTS ++ *************************************************************************) ++ ++let stmt_hardware = [ indent ++ . key "hardware" ++ . sep_spc ++ . [ label "type" . store /ethernet|tokenring|fddi/ ] ++ . sep_spc ++ . [ label "address" . store /[a-fA-F0-9:-]+/ ] ++ . sep_scl ++ . eos ] ++ ++(************************************************************************ ++ * SET STATEMENTS ++ *************************************************************************) ++let stmt_set = [ indent ++ . key "set" ++ . sep_spc ++ . store word ++ . sep_spc ++ . Sep.equal ++ . sep_spc ++ . [ label "value" . sto_to_scl ] ++ . sep_scl ++ . eos ] ++ ++(************************************************************************ ++ * OPTION STATEMENTS ++ *************************************************************************) ++(* The general case is considering options as a list *) ++ ++ ++let stmt_option_value = /((array of[ \t]+)?(((un)?signed[ \t]+)?integer (8|16|32)|string|ip6?-address|boolean|domain-list|text)|encapsulate [A-Za-z0-9_.-]+)/ ++ ++let stmt_option_list = ([ label "arg" . bare ] | [ label "arg" . quote ]) ++ . ( sep_com . ([ label "arg" . bare ] | [ label "arg" . quote ]))* ++ ++let del_trail_spc = del /[ \t\n]*/ "" ++ ++let stmt_record = counter "record" . Util.del_str "{" ++ . sep_spc ++ . ([seq "record" . store stmt_option_value . sep_com]* ++ . [seq "record" . store stmt_option_value . del_trail_spc])? ++ . Util.del_str "}" ++ ++let stmt_option_code = [ label "label" . store word . sep_spc ] ++ . [ key "code" . sep_spc . store word ] ++ . sep_eq ++ . ([ label "type" . store stmt_option_value ] ++ |[ label "record" . stmt_record ]) ++ ++let stmt_option_basic = [ key word . sep_spc . stmt_option_list ] ++let stmt_option_extra = [ key word . sep_spc . store /true|false/ . sep_spc . stmt_option_list ] ++ ++let stmt_option_body = stmt_option_basic | stmt_option_extra ++ ++let stmt_option1 = [ indent ++ . key "option" ++ . sep_spc ++ . stmt_option_body ++ . sep_scl ++ . eos ] ++ ++let stmt_option2 = [ indent ++ . dels "option" . label "rfc-code" ++ . sep_spc ++ . stmt_option_code ++ . sep_scl ++ . eos ] ++ ++let stmt_option = stmt_option1 | stmt_option2 ++ ++(************************************************************************ ++ * SUBCLASS STATEMENTS ++ *************************************************************************) ++(* this statement is not well documented in the manual dhcpd.conf ++ we support basic use case *) ++ ++let stmt_subclass = [ indent . key "subclass" . sep_spc ++ . ( [ label "name" . bare_to_scl ]|[ label "name" . dquote_any ] ) ++ . sep_spc ++ . ( [ label "value" . bare_to_scl ]|[ label "value" . dquote_any ] ) ++ . sep_scl ++ . eos ] ++ ++ ++(************************************************************************ ++ * ALLOW/DENY STATEMENTS ++ *************************************************************************) ++(* We have to use special key for allow/deny members of ++ to avoid ambiguity in the put direction *) ++ ++let allow_deny_re = /unknown(-|[ ]+)clients/ ++ | /known(-|[ ]+)clients/ ++ | /all[ ]+clients/ ++ | /dynamic[ ]+bootp[ ]+clients/ ++ | /authenticated[ ]+clients/ ++ | /unauthenticated[ ]+clients/ ++ | "bootp" ++ | "booting" ++ | "duplicates" ++ | "declines" ++ | "client-updates" ++ | "leasequery" ++ ++let stmt_secu_re = "allow" ++ | "deny" ++ ++let del_allow = del /allow[ ]+members[ ]+of/ "allow members of" ++let del_deny = del /deny[ \t]+members[ \t]+of/ "deny members of" ++ ++(* bare is anything but whitespace, quote marks or semicolon. ++ * technically this should be locked down to mostly alphanumerics, but the ++ * idea right now is just to make things work. Also ideally I would use ++ * dquote_space but I had a whale of a time with it. It doesn't like ++ * semicolon termination and my attempts to fix that led me to 3 hours of ++ * frustration and back to this :) ++ *) ++let stmt_secu_tpl (l:lens) (s:string) = ++ [ indent . l . sep_spc . label s . bare_to_scl . sep_scl . eos ] | ++ [ indent . l . sep_spc . label s . dquote_any . sep_scl . eos ] ++ ++ ++let stmt_secu = [ indent . key stmt_secu_re . sep_spc . ++ store allow_deny_re . sep_scl . eos ] | ++ stmt_secu_tpl del_allow "allow-members-of" | ++ stmt_secu_tpl del_deny "deny-members-of" ++ ++(************************************************************************ ++ * MATCH STATEMENTS ++ *************************************************************************) ++ ++let sto_com = /[^ \t\n,\(\)][^,\(\)]*[^ \t\n,\(\)]|[^ \t\n,\(\)]+/ | word . /[ \t]*\([^)]*\)/ ++(* this is already the most complicated part of this module and it's about to ++ * get worse. match statements can be way more complicated than this ++ * ++ * examples: ++ * using or: ++ * match if ((option vendor-class-identifier="Banana Bready") or (option vendor-class-identifier="Cherry Sunfire")); ++ * unneeded parenthesis: ++ * match if (option vendor-class-identifier="Hello"); ++ * ++ * and of course the fact that the above two rules used one of infinately ++ * many potential options instead of a builtin function. ++ *) ++(* sto_com doesn't support quoted strings as arguments. It also doesn't ++ support single arguments (needs to match a comma) It will need to be ++ updated for lcase, ucase and log to be workable. ++ ++ it also doesn't support no arguments, so gethostbyname() doesn't work. ++ ++ option and config-option are considered operators. They should be matched ++ in stmt_entry but also available under "match if" and "if" conditionals ++ leased-address, host-decl-name, both take no args and return a value. We ++ might need to treat them as variable names in the parser. ++ ++ things like this may be near-impossible to parse even with recursion ++ because we have no way of knowing when or if a subfunction takes arguments ++ set ClientMac = binary-to-ascii(16, 8, ":", substring(hardware, 1, 6)); ++ ++ even if we could parse it, they could get arbitrarily complicated like: ++ binary-to-ascii(16, 8, ":", substring(hardware, 1, 6) and substring(hardware, 2, 3)); ++ ++ so at some point we may need to programmatically knock it off and tell ++ people to put weird stuff in an include file that augeas doesn't parse. ++ ++ the other option is to change the API to not parse the if statement at all, ++ just pull in the conditional as a string. ++ *) ++ ++let fct_re = "substring" | "binary-to-ascii" | "suffix" | "lcase" | "ucase" ++ | "gethostbyname" | "packet" ++ | "concat" | "reverse" | "encode-int" ++ | "extract-int" | "lease-time" | "client-state" | "exists" | "known" | "static" ++ | "pick-first-value" | "log" | "execute" ++ ++(* not needs to be different because it's a negation of whatever happens next *) ++let op_re = "~="|"="|"~~"|"and"|"or" ++ ++let fct_args = [ label "args" . dels "(" . sep_osp . ++ ([ label "arg" . store sto_com ] . [ label "arg" . sep_com . store sto_com ]+) . ++ sep_osp . dels ")" ] ++ ++let stmt_match_ifopt = [ dels "if" . sep_spc . key "option" . sep_spc . store word . ++ sep_eq . ([ label "value" . bare_to_scl ]|[ label "value" . dquote_any ]) ] ++ ++let stmt_match_func = [ store fct_re . sep_osp . label "function" . fct_args ] . ++ sep_eq . ([ label "value" . bare_to_scl ]|[ label "value" . dquote_any ]) ++ ++let stmt_match_pfv = [ label "function" . store "pick-first-value" . sep_spc . ++ dels "(" . sep_osp . ++ [ label "args" . ++ [ label "arg" . store sto_com ] . ++ [ sep_com . label "arg" . store sto_com ]+ ] . ++ dels ")" ] ++ ++let stmt_match_tpl (l:lens) = [ indent . key "match" . sep_spc . l . sep_scl . eos ] ++ ++let stmt_match = stmt_match_tpl (dels "if" . sep_spc . stmt_match_func | stmt_match_pfv | stmt_match_ifopt) ++ ++(************************************************************************ ++ * BLOCK STATEMENTS ++ *************************************************************************) ++(* Blocks doesn't support comments at the end of the closing bracket *) ++ ++let stmt_entry = stmt_secu ++ | stmt_option ++ | stmt_hardware ++ | stmt_range ++ | stmt_string ++ | stmt_integer ++ | stmt_noarg ++ | stmt_match ++ | stmt_subclass ++ | stmt_set ++ | empty ++ | comment ++ ++let stmt_block_noarg_re = "pool" | "group" ++ ++let stmt_block_noarg (body:lens) ++ = [ indent ++ . key stmt_block_noarg_re ++ . sep_obr ++ . body* ++ . sep_cbr ] ++ ++let stmt_block_arg_re = "host" ++ | "class" ++ | "shared-network" ++ | /failover[ ]+peer/ ++ | "zone" ++ | "group" ++ | "on" ++ ++let stmt_block_arg (body:lens) ++ = ([ indent . key stmt_block_arg_re . sep_spc . dquote_any . sep_obr . body* . sep_cbr ] ++ |[ indent . key stmt_block_arg_re . sep_spc . bare_to_scl . sep_obr . body* . sep_cbr ] ++ |[ indent . del /key/ "key" . label "key_block" . sep_spc . dquote_any . sep_obr . body* . sep_cbr . del /(;([ \t]*\n)*)?/ "" ] ++ |[ indent . del /key/ "key" . label "key_block" . sep_spc . bare_to_scl . sep_obr . body* . sep_cbr . del /(;([ \t]*\n)*)?/ "" ]) ++ ++let stmt_block_subnet (body:lens) ++ = [ indent ++ . key "subnet" ++ . sep_spc ++ . [ label "network" . store ip ] ++ . sep_spc ++ . [ key "netmask" . sep_spc . store ip ] ++ . sep_obr ++ . body* ++ . sep_cbr ] ++ ++let conditional (body:lens) = ++ let condition = /[^{ \r\t\n][^{\n]*[^{ \r\t\n]|[^{ \t\n\r]/ ++ in let elsif = [ indent ++ . Build.xchgs "elsif" "@elsif" ++ . sep_spc ++ . store condition ++ . sep_obr ++ . body* ++ . sep_cbr ] ++ in let else = [ indent ++ . Build.xchgs "else" "@else" ++ . sep_obr ++ . body* ++ . sep_cbr ] ++ in [ indent ++ . Build.xchgs "if" "@if" ++ . sep_spc ++ . store condition ++ . sep_obr ++ . body* ++ . sep_cbr ++ . elsif* ++ . else? ] ++ ++ ++let all_block (body:lens) = ++ let lns1 = stmt_block_subnet body in ++ let lns2 = stmt_block_arg body in ++ let lns3 = stmt_block_noarg body in ++ let lns4 = conditional body in ++ (lns1 | lns2 | lns3 | lns4 | stmt_entry) ++ ++let rec lns_staging = stmt_entry|all_block lns_staging ++let lns = (lns_staging)* +diff --git a/lenses/tests/test_dhcpd.aug b/lenses/tests/test_dhcpd.aug +index 0af337c2..96630296 100644 +--- a/lenses/tests/test_dhcpd.aug ++++ b/lenses/tests/test_dhcpd.aug +@@ -28,9 +28,6 @@ max-lease-time 7200; + # network, the authoritative directive should be uncommented. + authoritative; + +-allow booting; +-allow bootp; +- + # Use this to send dhcp log messages to a different log file (you also + # have to hack syslog.conf to complete the redirection). + log-facility local7; +@@ -182,12 +179,7 @@ fixed-address 10.1.1.1;}}" = + } + } + +-test lns get "group fan-tas_tic { }" = +- { "group" = "fan-tas_tic" } +- + test Dhcpd.stmt_secu get "allow members of \"foo\";" = { "allow-members-of" = "foo" } +-test Dhcpd.stmt_secu get "allow booting;" = { "allow" = "booting" } +-test Dhcpd.stmt_secu get "allow bootp;" = { "allow" = "bootp" } + test Dhcpd.stmt_option get "option voip-boot-server code 66 = string;" = + { "rfc-code" + { "label" = "voip-boot-server" } +@@ -195,30 +187,6 @@ test Dhcpd.stmt_option get "option voip-boot-server code 66 = string;" = + { "type" = "string" } + } + +-test Dhcpd.stmt_option get "option special-option code 25 = array of string;" = +- { "rfc-code" +- { "label" = "special-option" } +- { "code" = "25" } +- { "type" = "array of string" } +- } +- +-test Dhcpd.stmt_option get "option special-option code 25 = integer 32;" = +- { "rfc-code" +- { "label" = "special-option" } +- { "code" = "25" } +- { "type" = "integer 32" } +- } +- +- +-test Dhcpd.stmt_option get "option special-option code 25 = array of integer 32;" = +- { "rfc-code" +- { "label" = "special-option" } +- { "code" = "25" } +- { "type" = "array of integer 32" } +- } +- +- +- + test Dhcpd.lns get "authoritative; + log-facility local7; + ddns-update-style none; +@@ -274,7 +242,7 @@ failover peer \"redondance01\" { + } + } + { "next-server" = "10.1.1.1" } +- { "failover peer" = "redondance01" ++ { "failover peer" = "\"redondance01\"" + { "primary" } + { "address" = "10.1.1.1" } + { "port" = "647" } +@@ -291,26 +259,6 @@ failover peer \"redondance01\" { + { "load balance max seconds" = "3" } + } + +- +-(* test get and put for record types *) +-let record_test = "option test_records code 123 = { string, ip-address, integer 32, ip6-address, domain-list };" +- +-test Dhcpd.lns get record_test = +- { "rfc-code" +- { "label" = "test_records" } +- { "code" = "123" } +- { "record" +- { "1" = "string" } +- { "2" = "ip-address" } +- { "3" = "integer 32" } +- { "4" = "ip6-address" } +- { "5" = "domain-list" } +- } +- } +- +-test Dhcpd.lns put record_test after set "/rfc-code[1]/code" "124" = +- "option test_records code 124 = { string, ip-address, integer 32, ip6-address, domain-list };" +- + test Dhcpd.lns get " + option CallManager code 150 = ip-address; + option slp-directory-agent true 10.1.1.1, 10.2.2.2; +@@ -386,25 +334,6 @@ test Dhcpd.stmt_match get "match if substring (option dhcp-client-identifier, 1, + { "value" = "RAS" } + } + +-test Dhcpd.stmt_match get "match if suffix (option dhcp-client-identifier, 4) = \"RAS\";" = +- { "match" +- { "function" = "suffix" +- { "args" +- { "arg" = "option dhcp-client-identifier" } +- { "arg" = "4" } +- } +- } +- { "value" = "RAS" } +- } +- +-test Dhcpd.stmt_match get "match if option vendor-class-identifier=\"RAS\";" = +- { "match" +- { "option" = "vendor-class-identifier" +- { "value" = "RAS" } +- } +- } +- +- + test Dhcpd.lns get "match pick-first-value (option dhcp-client-identifier, hardware);" = + { "match" + { "function" = "pick-first-value" +@@ -436,26 +365,12 @@ test Dhcpd.stmt_match get "match if binary-to-ascii(16, 32, \"\", substring(hard + { "value" = "1525400" } + } + +-test Dhcpd.lns get "subclass allocation-class-1 1:8:0:2b:4c:39:ad;" = +- { "subclass" +- { "name" = "allocation-class-1" } +- { "value" = "1:8:0:2b:4c:39:ad" } +- } +- +- + test Dhcpd.lns get "subclass \"allocation-class-1\" 1:8:0:2b:4c:39:ad;" = + { "subclass" + { "name" = "allocation-class-1" } + { "value" = "1:8:0:2b:4c:39:ad" } + } + +-test Dhcpd.lns get "subclass \"quoted class\" \"quoted value\";" = +- { "subclass" +- { "name" = "quoted class" } +- { "value" = "quoted value" } +- } +- +- + (* overall test *) + test Dhcpd.lns put conf after rm "/x" = conf + +@@ -477,130 +392,3 @@ filename \"pxelinux.0\"; + test Dhcpd.lns put "subnet 172.16.0.0 netmask 255.255.255.0 { + }" after + set "subnet/filename" "pxelinux.0" = input311 +- +-(* GH issue #34: support conditional structures *) +-let gh34_empty = "if exists dhcp-parameter-request-list { +-}\n" +- +-test Dhcpd.lns get gh34_empty = +- { "@if" = "exists dhcp-parameter-request-list" } +- +-let gh34_empty_multi = "subnet 192.168.100.0 netmask 255.255.255.0 { +- if true { +- } elsif false { +- } else { +- } +-}\n" +- +-test Dhcpd.lns get gh34_empty_multi = +- { "subnet" +- { "network" = "192.168.100.0" } +- { "netmask" = "255.255.255.0" } +- { "@if" = "true" +- { "@elsif" = "false" } +- { "@else" } } +- } +- +-let gh34_simple = "if exists dhcp-parameter-request-list { +- default-lease-time 600; +- } else { +-default-lease-time 200; +-}\n" +- +-test Dhcpd.lns get gh34_simple = +- { "@if" = "exists dhcp-parameter-request-list" +- { "default-lease-time" = "600" } +- { "@else" +- { "default-lease-time" = "200" } } } +- +-test Dhcpd.lns get "omapi-key fookey;" = +- { "omapi-key" = "fookey" } +- +-(* almost all DHCP groups should support braces starting on the next line *) +-test Dhcpd.lns get "class introduction +-{ +-}" = +- { "class" = "introduction" } +- +-(* equals should work the same *) +-test Dhcpd.lns get "option test_records code 123 = +- string;" = +- { "rfc-code" +- { "label" = "test_records" } +- { "code" = "123" } +- { "type" = "string" } +- } +- +-test Dhcpd.lns get "deny members of \"Are things like () allowed?\";" = +- { "deny-members-of" = "Are things like () allowed?" } +- +-test Dhcpd.lns get "deny unknown clients;" = +- { "deny" = "unknown clients" } +-test Dhcpd.lns get "deny known-clients;" = +- { "deny" = "known-clients" } +- +-test Dhcpd.lns get "set ClientMac = binary-to-ascii(16, 8, \":\" , substring(hardware, 1, 6));" = +- { "set" = "ClientMac" +- { "value" = "binary-to-ascii(16, 8, \":\" , substring(hardware, 1, 6))" } +- } +- +-test Dhcpd.lns get "set myvariable = foo;" = +- { "set" = "myvariable" +- { "value" = "foo" } +- } +- +-test Dhcpd.stmt_hardware get "hardware fddi 00:01:02:03:04:05;" = +- { "hardware" +- { "type" = "fddi" } +- { "address" = "00:01:02:03:04:05" } +- } +- +-test Dhcpd.lns get "on commit +-{ +- set test = thing; +-}" = +- { "on" = "commit" +- { "set" = "test" +- { "value" = "thing" } +- } +- } +- +-(* key block get/put/set test *) +-let key_tests = "key sample { +- algorithm hmac-md5; +- secret \"secret==\"; +-} +- +-key \"interesting\" { }; +- +-key \"third key\" { +- secret \"two==\"; +-}" +- +-test Dhcpd.lns get key_tests = +- { "key_block" = "sample" +- { "algorithm" = "hmac-md5" } +- { "secret" = "secret==" } +- } +- { "key_block" = "interesting" } +- { "key_block" = "third key" +- { "secret" = "two==" } +- } +- +-test Dhcpd.lns put key_tests after set "/key_block[1]" "sample2" = +- "key sample2 { +- algorithm hmac-md5; +- secret \"secret==\"; +-} +- +-key \"interesting\" { }; +- +-key \"third key\" { +- secret \"two==\"; +-}" +- +-test Dhcpd.lns get "group \"hello\" { }" = +- { "group" = "hello" } +- +-test Dhcpd.lns get "class \"testing class with spaces and quotes and ()\" {}" = +- { "class" = "testing class with spaces and quotes and ()" } +diff --git a/lenses/tests/test_dhcpd_140.aug b/lenses/tests/test_dhcpd_140.aug +new file mode 100644 +index 00000000..9d6fdc88 +--- /dev/null ++++ b/lenses/tests/test_dhcpd_140.aug +@@ -0,0 +1,606 @@ ++module Test_dhcpd_140 = ++ ++let lns = Dhcpd_140.lns ++ ++let conf = "# ++# Sample configuration file for ISC dhcpd for Debian ++# ++# Attention: If /etc/ltsp/dhcpd.conf exists, that will be used as ++# configuration file instead of this file. ++# ++# $Id: dhcpd.conf,v 1.1.1.1 2002/05/21 00:07:44 peloy Exp $ ++# ++ ++# The ddns-updates-style parameter controls whether or not the server will ++# attempt to do a DNS update when a lease is confirmed. We default to the ++# behavior of the version 2 packages ('none', since DHCP v2 didn't ++# have support for DDNS.) ++ddns-update-style none; ++ ++# option definitions common to all supported networks... ++option domain-name \"example.org\"; ++option domain-name-servers ns1.example.org, ns2.example.org; ++ ++default-lease-time 600; ++max-lease-time 7200; ++ ++# If this DHCP server is the official DHCP server for the local ++# network, the authoritative directive should be uncommented. ++authoritative; ++ ++allow booting; ++allow bootp; ++ ++# Use this to send dhcp log messages to a different log file (you also ++# have to hack syslog.conf to complete the redirection). ++log-facility local7; ++ ++# No service will be given on this subnet, but declaring it helps the ++# DHCP server to understand the network topology. ++ ++subnet 10.152.187.0 netmask 255.255.255.0 { ++} ++ ++# This is a very basic subnet declaration. ++ ++subnet 10.254.239.0 netmask 255.255.255.224 { ++ range 10.254.239.10 10.254.239.20; ++ option routers rtr-239-0-1.example.org, rtr-239-0-2.example.org; ++} ++ ++# This declaration allows BOOTP clients to get dynamic addresses, ++# which we don't really recommend. ++ ++subnet 10.254.239.32 netmask 255.255.255.224 { ++ range dynamic-bootp 10.254.239.40 10.254.239.60; ++ option broadcast-address 10.254.239.31; ++ option routers rtr-239-32-1.example.org; ++} ++ ++# A slightly different configuration for an internal subnet. ++subnet 10.5.5.0 netmask 255.255.255.224 { ++ range 10.5.5.26 10.5.5.30; ++ option domain-name-servers ns1.internal.example.org; ++ option domain-name \"internal.example.org\"; ++ option routers 10.5.5.1; ++ option broadcast-address 10.5.5.31; ++ default-lease-time 600; ++ max-lease-time 7200; ++} ++ ++# Hosts which require special configuration options can be listed in ++# host statements. If no address is specified, the address will be ++# allocated dynamically (if possible), but the host-specific information ++# will still come from the host declaration. ++ ++host passacaglia { ++ hardware ethernet 0:0:c0:5d:bd:95; ++ filename \"vmunix.passacaglia\"; ++ server-name \"toccata.fugue.com\"; ++} ++ ++# Fixed IP addresses can also be specified for hosts. These addresses ++# should not also be listed as being available for dynamic assignment. ++# Hosts for which fixed IP addresses have been specified can boot using ++# BOOTP or DHCP. Hosts for which no fixed address is specified can only ++# be booted with DHCP, unless there is an address range on the subnet ++# to which a BOOTP client is connected which has the dynamic-bootp flag ++# set. ++host fantasia { ++ hardware ethernet 08:00:07:26:c0:a5; ++ fixed-address fantasia.fugue.com; ++} ++ ++# You can declare a class of clients and then do address allocation ++# based on that. The example below shows a case where all clients ++# in a certain class get addresses on the 10.17.224/24 subnet, and all ++# other clients get addresses on the 10.0.29/24 subnet. ++ ++#class \"foo\" { ++# match if substring (option vendor-class-identifier, 0, 4) = \"SUNW\"; ++#} ++ ++shared-network 224-29 { ++ subnet 10.17.224.0 netmask 255.255.255.0 { ++ option routers rtr-224.example.org; ++ } ++ subnet 10.0.29.0 netmask 255.255.255.0 { ++ option routers rtr-29.example.org; ++ } ++ pool { ++ allow members of \"foo\"; ++ range 10.17.224.10 10.17.224.250; ++ } ++ pool { ++ deny members of \"foo\"; ++ range 10.0.29.10 10.0.29.230; ++ } ++} ++" ++ ++test lns get "authoritative;" = { "authoritative" } ++test lns get "ddns-update-style none;" = { "ddns-update-style" = "none" } ++test lns get "option domain-name \"example.org\";" = ++ { "option" ++ { "domain-name" ++ { "arg" = "example.org" } ++ } ++ } ++ ++test lns get "option domain-name-servers ns1.example.org, ns2.example.org;" = ++ { "option" ++ { "domain-name-servers" ++ { "arg" = "ns1.example.org" } ++ { "arg" = "ns2.example.org" } ++ } ++ } ++ ++test lns get "default-lease-time 600;" = { "default-lease-time" = "600" } ++test lns get "range 10.254.239.60;" = ++{ "range" ++ { "to" = "10.254.239.60" } ++ } ++ ++test lns get "range dynamic-bootp 10.254.239.60;" = ++ { "range" ++ { "flag" = "dynamic-bootp" } ++ { "to" = "10.254.239.60" } ++ } ++ ++test lns get "range dynamic-bootp 10.254.239.40 10.254.239.60;" = ++ { "range" ++ { "flag" = "dynamic-bootp" } ++ { "from" = "10.254.239.40" } ++ { "to" = "10.254.239.60" } ++ } ++ ++test lns get "subnet 10.152.187.0 netmask 255.255.255.0 {}\n" = ++ { "subnet" ++ { "network" = "10.152.187.0" } ++ { "netmask" = "255.255.255.0" } ++ } ++ ++test lns get " pool { ++ pool { ++ ++ } ++} ++" = ++ { "pool" ++ { "pool" } ++ } ++ ++test lns get "group { host some-host {hardware ethernet 00:00:aa:bb:cc:dd; ++fixed-address 10.1.1.1;}}" = ++ { "group" ++ { "host" = "some-host" ++ { "hardware" ++ { "type" = "ethernet" } ++ { "address" = "00:00:aa:bb:cc:dd" } ++ } ++ { "fixed-address" = "10.1.1.1" } ++ } ++ } ++ ++test lns get "group fan-tas_tic { }" = ++ { "group" = "fan-tas_tic" } ++ ++test Dhcpd_140.stmt_secu get "allow members of \"foo\";" = { "allow-members-of" = "foo" } ++test Dhcpd_140.stmt_secu get "allow booting;" = { "allow" = "booting" } ++test Dhcpd_140.stmt_secu get "allow bootp;" = { "allow" = "bootp" } ++test Dhcpd_140.stmt_option get "option voip-boot-server code 66 = string;" = ++ { "rfc-code" ++ { "label" = "voip-boot-server" } ++ { "code" = "66" } ++ { "type" = "string" } ++ } ++ ++test Dhcpd_140.stmt_option get "option special-option code 25 = array of string;" = ++ { "rfc-code" ++ { "label" = "special-option" } ++ { "code" = "25" } ++ { "type" = "array of string" } ++ } ++ ++test Dhcpd_140.stmt_option get "option special-option code 25 = integer 32;" = ++ { "rfc-code" ++ { "label" = "special-option" } ++ { "code" = "25" } ++ { "type" = "integer 32" } ++ } ++ ++ ++test Dhcpd_140.stmt_option get "option special-option code 25 = array of integer 32;" = ++ { "rfc-code" ++ { "label" = "special-option" } ++ { "code" = "25" } ++ { "type" = "array of integer 32" } ++ } ++ ++ ++ ++test Dhcpd_140.lns get "authoritative; ++log-facility local7; ++ddns-update-style none; ++default-lease-time 21600; ++max-lease-time 43200; ++ ++# Additional options for VOIP ++option voip-boot-server code 66 = string; ++option voip-vlan-id code 128 = string; ++" = ++ { "authoritative" } ++ { "log-facility" = "local7" } ++ { "ddns-update-style" = "none" } ++ { "default-lease-time" = "21600" } ++ { "max-lease-time" = "43200" ++ { "#comment" = "Additional options for VOIP" } ++ } ++ { "rfc-code" ++ { "label" = "voip-boot-server" } ++ { "code" = "66" } ++ { "type" = "string" } ++ } ++ { "rfc-code" ++ { "label" = "voip-vlan-id" } ++ { "code" = "128" } ++ { "type" = "string" } ++ } ++ ++ ++test Dhcpd_140.lns get " ++option domain-name-servers 10.1.1.1, 10.11.2.1, 10.1.3.1; ++next-server 10.1.1.1; ++ ++failover peer \"redondance01\" { ++ primary; ++ address 10.1.1.1; ++ port 647; ++ peer address 10.1.1.1; ++ peer port 647; ++ max-response-delay 20; ++ max-unacked-updates 10; ++ mclt 3600; #comment. ++ split 128; #comment. ++ load balance max seconds 3; ++ } ++" = ++ { } ++ { "option" ++ { "domain-name-servers" ++ { "arg" = "10.1.1.1" } ++ { "arg" = "10.11.2.1" } ++ { "arg" = "10.1.3.1" } ++ } ++ } ++ { "next-server" = "10.1.1.1" } ++ { "failover peer" = "redondance01" ++ { "primary" } ++ { "address" = "10.1.1.1" } ++ { "port" = "647" } ++ { "peer address" = "10.1.1.1" } ++ { "peer port" = "647" } ++ { "max-response-delay" = "20" } ++ { "max-unacked-updates" = "10" } ++ { "mclt" = "3600" ++ { "#comment" = "comment." } ++ } ++ { "split" = "128" ++ { "#comment" = "comment." } ++ } ++ { "load balance max seconds" = "3" } ++ } ++ ++ ++(* test get and put for record types *) ++let record_test = "option test_records code 123 = { string, ip-address, integer 32, ip6-address, domain-list };" ++ ++test Dhcpd_140.lns get record_test = ++ { "rfc-code" ++ { "label" = "test_records" } ++ { "code" = "123" } ++ { "record" ++ { "1" = "string" } ++ { "2" = "ip-address" } ++ { "3" = "integer 32" } ++ { "4" = "ip6-address" } ++ { "5" = "domain-list" } ++ } ++ } ++ ++test Dhcpd_140.lns put record_test after set "/rfc-code[1]/code" "124" = ++ "option test_records code 124 = { string, ip-address, integer 32, ip6-address, domain-list };" ++ ++test Dhcpd_140.lns get " ++option CallManager code 150 = ip-address; ++option slp-directory-agent true 10.1.1.1, 10.2.2.2; ++option slp-service-scope true \"SLP-GLOBAL\"; ++option nds-context \"EXAMPLE\"; ++option nds-tree-name \"EXAMPLE\"; ++" = ++ { } ++ { "rfc-code" ++ { "label" = "CallManager" } ++ { "code" = "150" } ++ { "type" = "ip-address" } ++ } ++ { "option" ++ { "slp-directory-agent" = "true" ++ { "arg" = "10.1.1.1" } ++ { "arg" = "10.2.2.2" } ++ } ++ } ++ { "option" ++ { "slp-service-scope" = "true" ++ { "arg" = "SLP-GLOBAL" } ++ } ++ } ++ { "option" ++ { "nds-context" ++ { "arg" = "EXAMPLE" } ++ } ++ } ++ { "option" ++ { "nds-tree-name" ++ { "arg" = "EXAMPLE" } ++ } ++ } ++ ++ ++test Dhcpd_140.lns get "option voip-vlan-id \"VLAN=1234;\";" = ++ { "option" ++ { "voip-vlan-id" ++ { "arg" = "VLAN=1234;" } ++ } ++ } ++ ++test Dhcpd_140.lns get "option domain-name \"x.example.com y.example.com z.example.com\";" = ++ { "option" ++ { "domain-name" ++ { "arg" = "x.example.com y.example.com z.example.com" } ++ } ++ } ++ ++test Dhcpd_140.lns get "include \"/etc/dhcpd.master\";" = ++ { "include" = "/etc/dhcpd.master" } ++ ++test Dhcpd_140.lns put "\n" after set "/include" "/etc/dhcpd.master" = ++ "\ninclude \"/etc/dhcpd.master\";\n" ++ ++test Dhcpd_140.fct_args get "(option dhcp-client-identifier, 1, 3)" = ++ { "args" ++ { "arg" = "option dhcp-client-identifier" } ++ { "arg" = "1" } ++ { "arg" = "3" } ++ } ++ ++test Dhcpd_140.stmt_match get "match if substring (option dhcp-client-identifier, 1, 3) = \"RAS\";" = ++ { "match" ++ { "function" = "substring" ++ { "args" ++ { "arg" = "option dhcp-client-identifier" } ++ { "arg" = "1" } ++ { "arg" = "3" } ++ } ++ } ++ { "value" = "RAS" } ++ } ++ ++test Dhcpd_140.stmt_match get "match if suffix (option dhcp-client-identifier, 4) = \"RAS\";" = ++ { "match" ++ { "function" = "suffix" ++ { "args" ++ { "arg" = "option dhcp-client-identifier" } ++ { "arg" = "4" } ++ } ++ } ++ { "value" = "RAS" } ++ } ++ ++test Dhcpd_140.stmt_match get "match if option vendor-class-identifier=\"RAS\";" = ++ { "match" ++ { "option" = "vendor-class-identifier" ++ { "value" = "RAS" } ++ } ++ } ++ ++ ++test Dhcpd_140.lns get "match pick-first-value (option dhcp-client-identifier, hardware);" = ++ { "match" ++ { "function" = "pick-first-value" ++ { "args" ++ { "arg" = "option dhcp-client-identifier" } ++ { "arg" = "hardware" } ++ } ++ } ++ } ++ ++test Dhcpd_140.fct_args get "(16, 32, \"\", substring(hardware, 0, 4))" = ++ { "args" ++ { "arg" = "16" } ++ { "arg" = "32" } ++ { "arg" = "\"\"" } ++ { "arg" = "substring(hardware, 0, 4)" } ++ } ++ ++test Dhcpd_140.stmt_match get "match if binary-to-ascii(16, 32, \"\", substring(hardware, 0, 4)) = \"1525400\";" = ++ { "match" ++ { "function" = "binary-to-ascii" ++ { "args" ++ { "arg" = "16" } ++ { "arg" = "32" } ++ { "arg" = "\"\"" } ++ { "arg" = "substring(hardware, 0, 4)" } ++ } ++ } ++ { "value" = "1525400" } ++ } ++ ++test Dhcpd_140.lns get "subclass allocation-class-1 1:8:0:2b:4c:39:ad;" = ++ { "subclass" ++ { "name" = "allocation-class-1" } ++ { "value" = "1:8:0:2b:4c:39:ad" } ++ } ++ ++ ++test Dhcpd_140.lns get "subclass \"allocation-class-1\" 1:8:0:2b:4c:39:ad;" = ++ { "subclass" ++ { "name" = "allocation-class-1" } ++ { "value" = "1:8:0:2b:4c:39:ad" } ++ } ++ ++test Dhcpd_140.lns get "subclass \"quoted class\" \"quoted value\";" = ++ { "subclass" ++ { "name" = "quoted class" } ++ { "value" = "quoted value" } ++ } ++ ++ ++(* overall test *) ++test Dhcpd_140.lns put conf after rm "/x" = conf ++ ++(* bug #293: primary should support argument *) ++let input293 = "zone EXAMPLE.ORG. { ++ primary 127.0.0.1; ++}" ++ ++test Dhcpd_140.lns get input293 = ++ { "zone" = "EXAMPLE.ORG." ++ { "primary" = "127.0.0.1" } ++ } ++ ++(* bug #311: filename should be quoted *) ++let input311 = "subnet 172.16.0.0 netmask 255.255.255.0 { ++filename \"pxelinux.0\"; ++}" ++ ++test Dhcpd_140.lns put "subnet 172.16.0.0 netmask 255.255.255.0 { ++}" after ++ set "subnet/filename" "pxelinux.0" = input311 ++ ++(* GH issue #34: support conditional structures *) ++let gh34_empty = "if exists dhcp-parameter-request-list { ++}\n" ++ ++test Dhcpd_140.lns get gh34_empty = ++ { "@if" = "exists dhcp-parameter-request-list" } ++ ++let gh34_empty_multi = "subnet 192.168.100.0 netmask 255.255.255.0 { ++ if true { ++ } elsif false { ++ } else { ++ } ++}\n" ++ ++test Dhcpd_140.lns get gh34_empty_multi = ++ { "subnet" ++ { "network" = "192.168.100.0" } ++ { "netmask" = "255.255.255.0" } ++ { "@if" = "true" ++ { "@elsif" = "false" } ++ { "@else" } } ++ } ++ ++let gh34_simple = "if exists dhcp-parameter-request-list { ++ default-lease-time 600; ++ } else { ++default-lease-time 200; ++}\n" ++ ++test Dhcpd_140.lns get gh34_simple = ++ { "@if" = "exists dhcp-parameter-request-list" ++ { "default-lease-time" = "600" } ++ { "@else" ++ { "default-lease-time" = "200" } } } ++ ++test Dhcpd_140.lns get "omapi-key fookey;" = ++ { "omapi-key" = "fookey" } ++ ++(* almost all DHCP groups should support braces starting on the next line *) ++test Dhcpd_140.lns get "class introduction ++{ ++}" = ++ { "class" = "introduction" } ++ ++(* equals should work the same *) ++test Dhcpd_140.lns get "option test_records code 123 = ++ string;" = ++ { "rfc-code" ++ { "label" = "test_records" } ++ { "code" = "123" } ++ { "type" = "string" } ++ } ++ ++test Dhcpd_140.lns get "deny members of \"Are things like () allowed?\";" = ++ { "deny-members-of" = "Are things like () allowed?" } ++ ++test Dhcpd_140.lns get "deny unknown clients;" = ++ { "deny" = "unknown clients" } ++test Dhcpd_140.lns get "deny known-clients;" = ++ { "deny" = "known-clients" } ++ ++test Dhcpd_140.lns get "set ClientMac = binary-to-ascii(16, 8, \":\" , substring(hardware, 1, 6));" = ++ { "set" = "ClientMac" ++ { "value" = "binary-to-ascii(16, 8, \":\" , substring(hardware, 1, 6))" } ++ } ++ ++test Dhcpd_140.lns get "set myvariable = foo;" = ++ { "set" = "myvariable" ++ { "value" = "foo" } ++ } ++ ++test Dhcpd_140.stmt_hardware get "hardware fddi 00:01:02:03:04:05;" = ++ { "hardware" ++ { "type" = "fddi" } ++ { "address" = "00:01:02:03:04:05" } ++ } ++ ++test Dhcpd_140.lns get "on commit ++{ ++ set test = thing; ++}" = ++ { "on" = "commit" ++ { "set" = "test" ++ { "value" = "thing" } ++ } ++ } ++ ++(* key block get/put/set test *) ++let key_tests = "key sample { ++ algorithm hmac-md5; ++ secret \"secret==\"; ++} ++ ++key \"interesting\" { }; ++ ++key \"third key\" { ++ secret \"two==\"; ++}" ++ ++test Dhcpd_140.lns get key_tests = ++ { "key_block" = "sample" ++ { "algorithm" = "hmac-md5" } ++ { "secret" = "secret==" } ++ } ++ { "key_block" = "interesting" } ++ { "key_block" = "third key" ++ { "secret" = "two==" } ++ } ++ ++test Dhcpd_140.lns put key_tests after set "/key_block[1]" "sample2" = ++ "key sample2 { ++ algorithm hmac-md5; ++ secret \"secret==\"; ++} ++ ++key \"interesting\" { }; ++ ++key \"third key\" { ++ secret \"two==\"; ++}" ++ ++test Dhcpd_140.lns get "group \"hello\" { }" = ++ { "group" = "hello" } ++ ++test Dhcpd_140.lns get "class \"testing class with spaces and quotes and ()\" {}" = ++ { "class" = "testing class with spaces and quotes and ()" } +diff --git a/tests/Makefile.am b/tests/Makefile.am +index 387ac7d2..315cac9c 100644 +--- a/tests/Makefile.am ++++ b/tests/Makefile.am +@@ -58,6 +58,7 @@ lens_tests = \ + lens-device_map.sh \ + lens-dhclient.sh \ + lens-dhcpd.sh \ ++ lens-dhcpd_140.sh \ + lens-dns_zone.sh \ + lens-dnsmasq.sh \ + lens-dovecot.sh \ +-- +2.17.2 + diff --git a/SOURCES/0008-Slapd-revert-Slapd-module-to-1.1.0-compatible-add-Sl.patch b/SOURCES/0008-Slapd-revert-Slapd-module-to-1.1.0-compatible-add-Sl.patch new file mode 100644 index 0000000..6f2846a --- /dev/null +++ b/SOURCES/0008-Slapd-revert-Slapd-module-to-1.1.0-compatible-add-Sl.patch @@ -0,0 +1,418 @@ +From faf60bc7b1cb727482a17de9a2483998763978c0 Mon Sep 17 00:00:00 2001 +From: Dominic Cleal +Date: Fri, 12 Jun 2015 11:14:32 +0100 +Subject: [PATCH] Slapd: revert Slapd module to 1.1.0-compatible, add Slapd_140 + +In order to keep the default sshd config lens compatible with 1.1.0, +the lens from 1.4.0 has been kept in the Slapd_140 module and is not +loaded by default. Use aug_transform, augtool --transform etc. to use +it instead of Slapd. +--- + lenses/slapd.aug | 18 ++-- + lenses/slapd_140.aug | 158 ++++++++++++++++++++++++++++++++ + lenses/tests/test_slapd.aug | 55 +++-------- + lenses/tests/test_slapd_140.aug | 94 +++++++++++++++++++ + tests/Makefile.am | 1 + + 5 files changed, 273 insertions(+), 53 deletions(-) + create mode 100644 lenses/slapd_140.aug + create mode 100644 lenses/tests/test_slapd_140.aug + +diff --git a/lenses/slapd.aug b/lenses/slapd.aug +index e1195655..afe074b1 100644 +--- a/lenses/slapd.aug ++++ b/lenses/slapd.aug +@@ -18,6 +18,7 @@ let sep = del /[ \t\n]+/ " " + + let sto_to_eol = store /([^ \t\n].*[^ \t\n]|[^ \t\n])/ + let sto_to_spc = store /[^\\# \t\n]+/ ++let sto_to_by = store (/[^\\# \t\n]+/ - "by") + + let comment = Util.comment + let empty = Util.empty +@@ -27,14 +28,12 @@ let empty = Util.empty + *************************************************************************) + + let access_re = "access to" +-let control_re = "stop" | "continue" | "break" +-let what = [ spc . label "access" +- . store (/[^\\# \t\n]+/ - ("by" | control_re)) ] ++let who = [ spc . label "who" . sto_to_spc ] ++let what = [ spc . label "what" . sto_to_spc ] + + (* TODO: parse the control field, see man slapd.access (5) *) +-let control = [ spc . label "control" . store control_re ] +-let by = [ sep . key "by" . spc . sto_to_spc +- . what? . control? ] ++let control = [ spc . label "control" . sto_to_by ] ++let by = [ sep . key "by". who . what. control? ] + + let access = [ key access_re . spc. sto_to_spc . by+ . eol ] + +@@ -134,21 +133,18 @@ let database_re = "suffix" + | "restrict" + | "rootdn" + | "rootpw" ++ | "suffix" + | "subordinate" + | "syncrepl rid" + | "updatedn" + | "updateref" + | database_hdb + +-let database_entry = +- let val = Quote.double_opt +- in Build.key_value_line database_re Sep.space val +- + let database = [ key "database" + . spc + . sto_to_eol + . eol +- . (comment|empty|database_entry|access)* ] ++ . (comment|empty|Build.key_ws_value database_re|access)* ] + + (************************************************************************ + * LENS +diff --git a/lenses/slapd_140.aug b/lenses/slapd_140.aug +new file mode 100644 +index 00000000..8d1cd074 +--- /dev/null ++++ b/lenses/slapd_140.aug +@@ -0,0 +1,158 @@ ++(* Slapd module for Augeas ++ This module is compatible with Augeas 1.4.0, but is not loaded by default. ++ ++ Author: Free Ekanayaka ++ ++ Reference: man slapd.conf(5), man slapd.access (5) ++ ++*) ++ ++module Slapd_140 = ++ ++(************************************************************************ ++ * USEFUL PRIMITIVES ++ *************************************************************************) ++ ++let eol = Util.eol ++let spc = Util.del_ws_spc ++let sep = del /[ \t\n]+/ " " ++ ++let sto_to_eol = store /([^ \t\n].*[^ \t\n]|[^ \t\n])/ ++let sto_to_spc = store /[^\\# \t\n]+/ ++ ++let comment = Util.comment ++let empty = Util.empty ++ ++(************************************************************************ ++ * ACCESS TO ++ *************************************************************************) ++ ++let access_re = "access to" ++let control_re = "stop" | "continue" | "break" ++let what = [ spc . label "access" ++ . store (/[^\\# \t\n]+/ - ("by" | control_re)) ] ++ ++(* TODO: parse the control field, see man slapd.access (5) *) ++let control = [ spc . label "control" . store control_re ] ++let by = [ sep . key "by" . spc . sto_to_spc ++ . what? . control? ] ++ ++let access = [ key access_re . spc. sto_to_spc . by+ . eol ] ++ ++(************************************************************************ ++ * GLOBAL ++ *************************************************************************) ++ ++(* TODO: parse special field separately, see man slapd.conf (5) *) ++let global_re = "allow" ++ | "argsfile" ++ | "attributeoptions" ++ | "attributetype" ++ | "authz-policy" ++ | "ldap" ++ | "dn" ++ | "concurrency" ++ | "cron_max_pending" ++ | "conn_max_pending_auth" ++ | "defaultsearchbase" ++ | "disallow" ++ | "ditcontentrule" ++ | "gentlehup" ++ | "idletimeout" ++ | "include" ++ | "index_substr_if_minlen" ++ | "index_substr_if_maxlen" ++ | "index_substr_any_len" ++ | "index_substr_any_step" ++ | "localSSF" ++ | "loglevel" ++ | "moduleload" ++ | "modulepath" ++ | "objectclass" ++ | "objectidentifier" ++ | "password-hash" ++ | "password-crypt-salt-format" ++ | "pidfile" ++ | "referral" ++ | "replica-argsfile" ++ | "replica-pidfile" ++ | "replicationinterval" ++ | "require" ++ | "reverse-lookup" ++ | "rootDSE" ++ | "sasl-host " ++ | "sasl-realm" ++ | "sasl-secprops" ++ | "schemadn" ++ | "security" ++ | "sizelimit" ++ | "sockbuf_max_incoming " ++ | "sockbuf_max_incoming_auth" ++ | "threads" ++ | "timelimit time" ++ | "tool-threads" ++ | "TLSCipherSuite" ++ | "TLSCACertificateFile" ++ | "TLSCACertificatePath" ++ | "TLSCertificateFile" ++ | "TLSCertificateKeyFile" ++ | "TLSDHParamFile" ++ | "TLSRandFile" ++ | "TLSVerifyClient" ++ | "TLSCRLCheck" ++ | "backend" ++ ++let global = Build.key_ws_value global_re ++ ++(************************************************************************ ++ * DATABASE ++ *************************************************************************) ++ ++(* TODO: support all types of database backend *) ++let database_hdb = "cachesize" ++ | "cachefree" ++ | "checkpoint" ++ | "dbconfig" ++ | "dbnosync" ++ | "directory" ++ | "dirtyread" ++ | "idlcachesize" ++ | "index" ++ | "linearindex" ++ | "lockdetect" ++ | "mode" ++ | "searchstack" ++ | "shm_key" ++ ++let database_re = "suffix" ++ | "lastmod" ++ | "limits" ++ | "maxderefdepth" ++ | "overlay" ++ | "readonly" ++ | "replica uri" ++ | "replogfile" ++ | "restrict" ++ | "rootdn" ++ | "rootpw" ++ | "subordinate" ++ | "syncrepl rid" ++ | "updatedn" ++ | "updateref" ++ | database_hdb ++ ++let database_entry = ++ let val = Quote.double_opt ++ in Build.key_value_line database_re Sep.space val ++ ++let database = [ key "database" ++ . spc ++ . sto_to_eol ++ . eol ++ . (comment|empty|database_entry|access)* ] ++ ++(************************************************************************ ++ * LENS ++ *************************************************************************) ++ ++let lns = (comment|empty|global|access)* . (database)* +diff --git a/lenses/tests/test_slapd.aug b/lenses/tests/test_slapd.aug +index a4bbb4e9..e477342a 100644 +--- a/lenses/tests/test_slapd.aug ++++ b/lenses/tests/test_slapd.aug +@@ -48,47 +48,18 @@ test Slapd.lns get conf = + { "database" = "hdb" + {} + { "#comment" = "The base of your directory in database #1" } +- { "suffix" = "dc=nodomain" } ++ { "suffix" = "\"dc=nodomain\"" } + {} + { "access to" = "attrs=userPassword,shadowLastChange" +- { "by" = "dn=\"cn=admin,dc=nodomain\"" +- { "access" = "write" } } +- { "by" = "anonymous" +- { "access" = "auth" } } +- { "by" = "self" +- { "access" = "write" } } +- { "by" = "*" +- { "access" = "none" } } } } +- +-(* Test: Slapd.lns +- Full access test with who/access/control *) +-test Slapd.lns get "access to dn.subtree=\"dc=example,dc=com\" +- by self write stop\n" = +- { "access to" = "dn.subtree=\"dc=example,dc=com\"" +- { "by" = "self" +- { "access" = "write" } +- { "control" = "stop" } } } +- +-(* Test: Slapd.lns +- access test with who *) +-test Slapd.lns get "access to dn.subtree=\"dc=example,dc=com\" +- by self\n" = +- { "access to" = "dn.subtree=\"dc=example,dc=com\"" +- { "by" = "self" } } +- +-(* Test: Slapd.lns +- access test with who/access *) +-test Slapd.lns get "access to dn.subtree=\"dc=example,dc=com\" +- by self write\n" = +- { "access to" = "dn.subtree=\"dc=example,dc=com\"" +- { "by" = "self" +- { "access" = "write" } } } +- +-(* Test: Slapd.lns +- access test with who/control *) +-test Slapd.lns get "access to dn.subtree=\"dc=example,dc=com\" +- by self stop\n" = +- { "access to" = "dn.subtree=\"dc=example,dc=com\"" +- { "by" = "self" +- { "control" = "stop" } } } +- ++ { "by" ++ { "who" = "dn=\"cn=admin,dc=nodomain\"" } ++ { "what" = "write" } } ++ { "by" ++ { "who" = "anonymous" } ++ { "what" = "auth" } } ++ { "by" ++ { "who" = "self" } ++ { "what" = "write" } } ++ { "by" ++ { "who" = "*" } ++ { "what" = "none" } } } } +diff --git a/lenses/tests/test_slapd_140.aug b/lenses/tests/test_slapd_140.aug +new file mode 100644 +index 00000000..0118f030 +--- /dev/null ++++ b/lenses/tests/test_slapd_140.aug +@@ -0,0 +1,94 @@ ++module Test_slapd_140 = ++ ++let conf = "# This is the main slapd configuration file. See slapd.conf(5) for more ++# info on the configuration options. ++ ++####################################################################### ++# Global Directives: ++ ++# Features to permit ++#allow bind_v2 ++ ++# Schema and objectClass definitions ++include /etc/ldap/schema/core.schema ++ ++####################################################################### ++# Specific Directives for database #1, of type hdb: ++# Database specific directives apply to this databasse until another ++# 'database' directive occurs ++database hdb ++ ++# The base of your directory in database #1 ++suffix \"dc=nodomain\" ++ ++access to attrs=userPassword,shadowLastChange ++ by dn=\"cn=admin,dc=nodomain\" write ++ by anonymous auth ++ by self write ++ by * none ++" ++ ++test Slapd_140.lns get conf = ++ { "#comment" = "This is the main slapd configuration file. See slapd.conf(5) for more" } ++ { "#comment" = "info on the configuration options." } ++ {} ++ { "#comment" = "######################################################################" } ++ { "#comment" = "Global Directives:"} ++ {} ++ { "#comment" = "Features to permit" } ++ { "#comment" = "allow bind_v2" } ++ {} ++ { "#comment" = "Schema and objectClass definitions" } ++ { "include" = "/etc/ldap/schema/core.schema" } ++ {} ++ { "#comment" = "######################################################################" } ++ { "#comment" = "Specific Directives for database #1, of type hdb:" } ++ { "#comment" = "Database specific directives apply to this databasse until another" } ++ { "#comment" = "'database' directive occurs" } ++ { "database" = "hdb" ++ {} ++ { "#comment" = "The base of your directory in database #1" } ++ { "suffix" = "dc=nodomain" } ++ {} ++ { "access to" = "attrs=userPassword,shadowLastChange" ++ { "by" = "dn=\"cn=admin,dc=nodomain\"" ++ { "access" = "write" } } ++ { "by" = "anonymous" ++ { "access" = "auth" } } ++ { "by" = "self" ++ { "access" = "write" } } ++ { "by" = "*" ++ { "access" = "none" } } } } ++ ++(* Test: Slapd_140.lns ++ Full access test with who/access/control *) ++test Slapd_140.lns get "access to dn.subtree=\"dc=example,dc=com\" ++ by self write stop\n" = ++ { "access to" = "dn.subtree=\"dc=example,dc=com\"" ++ { "by" = "self" ++ { "access" = "write" } ++ { "control" = "stop" } } } ++ ++(* Test: Slapd_140.lns ++ access test with who *) ++test Slapd_140.lns get "access to dn.subtree=\"dc=example,dc=com\" ++ by self\n" = ++ { "access to" = "dn.subtree=\"dc=example,dc=com\"" ++ { "by" = "self" } } ++ ++(* Test: Slapd_140.lns ++ access test with who/access *) ++test Slapd_140.lns get "access to dn.subtree=\"dc=example,dc=com\" ++ by self write\n" = ++ { "access to" = "dn.subtree=\"dc=example,dc=com\"" ++ { "by" = "self" ++ { "access" = "write" } } } ++ ++(* Test: Slapd_140.lns ++ access test with who/control *) ++test Slapd_140.lns get "access to dn.subtree=\"dc=example,dc=com\" ++ by self stop\n" = ++ { "access to" = "dn.subtree=\"dc=example,dc=com\"" ++ { "by" = "self" ++ { "control" = "stop" } } } ++ +diff --git a/tests/Makefile.am b/tests/Makefile.am +index 315cac9c..65d8993e 100644 +--- a/tests/Makefile.am ++++ b/tests/Makefile.am +@@ -182,6 +182,7 @@ lens_tests = \ + lens-simplevars.sh \ + lens-sip_conf.sh \ + lens-slapd.sh \ ++ lens-slapd_140.sh \ + lens-smbusers.sh \ + lens-solaris_system.sh \ + lens-soma.sh \ +-- +2.17.2 + diff --git a/SOURCES/0009-Rhsm-new-lens-to-parse-subscription-manager-s-rhsm.c.patch b/SOURCES/0009-Rhsm-new-lens-to-parse-subscription-manager-s-rhsm.c.patch new file mode 100644 index 0000000..d5f28ac --- /dev/null +++ b/SOURCES/0009-Rhsm-new-lens-to-parse-subscription-manager-s-rhsm.c.patch @@ -0,0 +1,258 @@ +From a90c028eae871422588037ea1a21aff080f77fd2 Mon Sep 17 00:00:00 2001 +From: Dominic Cleal +Date: Fri, 3 Jul 2015 12:05:30 +0100 +Subject: [PATCH] Rhsm: new lens to parse subscription-manager's rhsm.conf + +(cherry picked from commit abdb9fbc4e8c0975f51a62e34ee2e22ed2d5c39f) + +Conflicts: + NEWS +--- + doc/naturaldocs/conf/lenses/Menu.txt | 2 + + lenses/rhsm.aug | 42 ++++++++ + lenses/tests/test_rhsm.aug | 151 +++++++++++++++++++++++++++ + tests/Makefile.am | 1 + + 4 files changed, 196 insertions(+) + create mode 100644 lenses/rhsm.aug + create mode 100644 lenses/tests/test_rhsm.aug + +diff --git a/doc/naturaldocs/conf/lenses/Menu.txt b/doc/naturaldocs/conf/lenses/Menu.txt +index c245446b..e74cd13a 100644 +--- a/doc/naturaldocs/conf/lenses/Menu.txt ++++ b/doc/naturaldocs/conf/lenses/Menu.txt +@@ -151,6 +151,7 @@ Group: Specific Modules { + File: Redis (redis.aug) + File: Reprepro_Uploaders (reprepro_uploaders.aug) + File: Resolv (resolv.aug) ++ File: Rhsm (rhsm.aug) + File: Rmt (rmt.aug) + File: Rsyslog (rsyslog.aug) + File: Schroot (schroot.aug) +@@ -261,6 +262,7 @@ Group: Tests and Examples { + File: Test_Rabbitmq (tests/test_rabbitmq.aug) + File: Test_Redis (tests/test_redis.aug) + File: Test_Reprepro_Uploaders (tests/test_reprepro_uploaders.aug) ++ File: Test_Rhsm (tests/test_rhsm.aug) + File: Test_Rmt (tests/test_rmt.aug) + File: Test_Rsyslog (tests/test_rsyslog.aug) + File: Test_Simplelines (tests/test_simplelines.aug) +diff --git a/lenses/rhsm.aug b/lenses/rhsm.aug +new file mode 100644 +index 00000000..56cc82ea +--- /dev/null ++++ b/lenses/rhsm.aug +@@ -0,0 +1,42 @@ ++(* ++Module: Rhsm ++ Parses subscription-manager config files ++ ++Author: Dominic Cleal ++ ++About: Reference ++ This lens tries to keep as close as possible to rhsm.conf(5) and ++ Python's SafeConfigParser. All settings must be in sections without ++ indentation. Semicolons and hashes are permitted for comments. ++ ++About: License ++ This file is licenced under the LGPL v2+, like the rest of Augeas. ++ ++About: Lens Usage ++ To be documented ++ ++About: Configuration files ++ This lens applies to: ++ /etc/rhsm/rhsm.conf ++ ++ See . ++*) ++ ++module Rhsm = ++ autoload xfm ++ ++(* Semicolons and hashes are permitted for comments *) ++let comment = IniFile.comment IniFile.comment_re "#" ++(* Equals and colons are permitted for separators *) ++let sep = IniFile.sep IniFile.sep_re IniFile.sep_default ++ ++(* All settings must be in sections without indentation *) ++let entry = IniFile.entry_multiline IniFile.entry_re sep comment ++let title = IniFile.title IniFile.record_re ++let record = IniFile.record title entry ++ ++let lns = IniFile.lns record comment ++ ++let filter = incl "/etc/rhsm/rhsm.conf" ++ ++let xfm = transform lns filter +diff --git a/lenses/tests/test_rhsm.aug b/lenses/tests/test_rhsm.aug +new file mode 100644 +index 00000000..219a5be7 +--- /dev/null ++++ b/lenses/tests/test_rhsm.aug +@@ -0,0 +1,151 @@ ++(* ++Module: Test_Rhsm ++ Provides unit tests and examples for the lens. ++*) ++ ++module Test_rhsm = ++ ++ (* Variable: conf ++ A full rhsm.conf *) ++ let conf = "# Red Hat Subscription Manager Configuration File: ++ ++# Unified Entitlement Platform Configuration ++[server] ++# Server hostname: ++hostname = subscription.rhn.redhat.com ++ ++# Server prefix: ++prefix = /subscription ++ ++# Server port: ++port = 443 ++ ++# Set to 1 to disable certificate validation: ++insecure = 0 ++ ++# Set the depth of certs which should be checked ++# when validating a certificate ++ssl_verify_depth = 3 ++ ++# an http proxy server to use ++proxy_hostname = ++ ++# port for http proxy server ++proxy_port = ++ ++# user name for authenticating to an http proxy, if needed ++proxy_user = ++ ++# password for basic http proxy auth, if needed ++proxy_password = ++ ++[rhsm] ++# Content base URL: ++baseurl= https://cdn.redhat.com ++ ++# Server CA certificate location: ++ca_cert_dir = /etc/rhsm/ca/ ++ ++# Default CA cert to use when generating yum repo configs: ++repo_ca_cert = %(ca_cert_dir)sredhat-uep.pem ++ ++# Where the certificates should be stored ++productCertDir = /etc/pki/product ++entitlementCertDir = /etc/pki/entitlement ++consumerCertDir = /etc/pki/consumer ++ ++# Manage generation of yum repositories for subscribed content: ++manage_repos = 1 ++ ++# Refresh repo files with server overrides on every yum command ++full_refresh_on_yum = 0 ++ ++# If set to zero, the client will not report the package profile to ++# the subscription management service. ++report_package_profile = 1 ++ ++# The directory to search for subscription manager plugins ++pluginDir = /usr/share/rhsm-plugins ++ ++# The directory to search for plugin configuration files ++pluginConfDir = /etc/rhsm/pluginconf.d ++ ++[rhsmcertd] ++# Interval to run cert check (in minutes): ++certCheckInterval = 240 ++# Interval to run auto-attach (in minutes): ++autoAttachInterval = 1440 ++" ++ ++ test Rhsm.lns get conf = ++ { "#comment" = "Red Hat Subscription Manager Configuration File:" } ++ { } ++ { "#comment" = "Unified Entitlement Platform Configuration" } ++ { "server" ++ { "#comment" = "Server hostname:" } ++ { "hostname" = "subscription.rhn.redhat.com" } ++ { } ++ { "#comment" = "Server prefix:" } ++ { "prefix" = "/subscription" } ++ { } ++ { "#comment" = "Server port:" } ++ { "port" = "443" } ++ { } ++ { "#comment" = "Set to 1 to disable certificate validation:" } ++ { "insecure" = "0" } ++ { } ++ { "#comment" = "Set the depth of certs which should be checked" } ++ { "#comment" = "when validating a certificate" } ++ { "ssl_verify_depth" = "3" } ++ { } ++ { "#comment" = "an http proxy server to use" } ++ { "proxy_hostname" } ++ { } ++ { "#comment" = "port for http proxy server" } ++ { "proxy_port" } ++ { } ++ { "#comment" = "user name for authenticating to an http proxy, if needed" } ++ { "proxy_user" } ++ { } ++ { "#comment" = "password for basic http proxy auth, if needed" } ++ { "proxy_password" } ++ { } ++ } ++ { "rhsm" ++ { "#comment" = "Content base URL:" } ++ { "baseurl" = "https://cdn.redhat.com" } ++ { } ++ { "#comment" = "Server CA certificate location:" } ++ { "ca_cert_dir" = "/etc/rhsm/ca/" } ++ { } ++ { "#comment" = "Default CA cert to use when generating yum repo configs:" } ++ { "repo_ca_cert" = "%(ca_cert_dir)sredhat-uep.pem" } ++ { } ++ { "#comment" = "Where the certificates should be stored" } ++ { "productCertDir" = "/etc/pki/product" } ++ { "entitlementCertDir" = "/etc/pki/entitlement" } ++ { "consumerCertDir" = "/etc/pki/consumer" } ++ { } ++ { "#comment" = "Manage generation of yum repositories for subscribed content:" } ++ { "manage_repos" = "1" } ++ { } ++ { "#comment" = "Refresh repo files with server overrides on every yum command" } ++ { "full_refresh_on_yum" = "0" } ++ { } ++ { "#comment" = "If set to zero, the client will not report the package profile to" } ++ { "#comment" = "the subscription management service." } ++ { "report_package_profile" = "1" } ++ { } ++ { "#comment" = "The directory to search for subscription manager plugins" } ++ { "pluginDir" = "/usr/share/rhsm-plugins" } ++ { } ++ { "#comment" = "The directory to search for plugin configuration files" } ++ { "pluginConfDir" = "/etc/rhsm/pluginconf.d" } ++ { } ++ } ++ { "rhsmcertd" ++ { "#comment" = "Interval to run cert check (in minutes):" } ++ { "certCheckInterval" = "240" } ++ { "#comment" = "Interval to run auto-attach (in minutes):" } ++ { "autoAttachInterval" = "1440" } ++ } +diff --git a/tests/Makefile.am b/tests/Makefile.am +index 65d8993e..4d2b2605 100644 +--- a/tests/Makefile.am ++++ b/tests/Makefile.am +@@ -167,6 +167,7 @@ lens_tests = \ + lens-redis.sh \ + lens-reprepro_uploaders.sh \ + lens-resolv.sh \ ++ lens-rhsm.sh \ + lens-rmt.sh \ + lens-rsyncd.sh \ + lens-rsyslog.sh \ +-- +2.17.2 + diff --git a/SOURCES/0010-Fix-sudoers-lens-recognize-match_group_by_gid.patch b/SOURCES/0010-Fix-sudoers-lens-recognize-match_group_by_gid.patch new file mode 100644 index 0000000..15481ba --- /dev/null +++ b/SOURCES/0010-Fix-sudoers-lens-recognize-match_group_by_gid.patch @@ -0,0 +1,29 @@ +From 9a65d8e4a428f05e392658fac498ea99d3b3405f Mon Sep 17 00:00:00 2001 +From: Luigi Toscano +Date: Thu, 24 Aug 2017 16:21:49 +0200 +Subject: [PATCH] Fix sudoers lens: recognize "match_group_by_gid" + +The option is now enabled by default in the default sudoers of +RHEL 7.4 (and probably soon CentOS 7). + +Closes #482 +--- + lenses/sudoers.aug | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/lenses/sudoers.aug b/lenses/sudoers.aug +index 7567772d..0437daae 100644 +--- a/lenses/sudoers.aug ++++ b/lenses/sudoers.aug +@@ -307,7 +307,7 @@ let parameter_flag_kw = "always_set_home" | "authenticate" | "env_editor" + | "tty_tickets" | "visiblepw" | "closefrom_override" + | "closefrom_override" | "compress_io" | "fast_glob" + | "log_input" | "log_output" | "pwfeedback" +- | "umask_override" | "use_pty" ++ | "umask_override" | "use_pty" | "match_group_by_gid" + + let parameter_flag = [ del_negate . negate_node? + . key parameter_flag_kw ] +-- +2.17.2 + diff --git a/SOURCES/0011-src-pathx.c-parse_name-correctly-handle-trailing-whi.patch b/SOURCES/0011-src-pathx.c-parse_name-correctly-handle-trailing-whi.patch new file mode 100644 index 0000000..6ccffd6 --- /dev/null +++ b/SOURCES/0011-src-pathx.c-parse_name-correctly-handle-trailing-whi.patch @@ -0,0 +1,162 @@ +From d157f330acfe94a1f61bf766b485beb0e0dd7177 Mon Sep 17 00:00:00 2001 +From: David Lutterkort +Date: Fri, 4 Aug 2017 17:13:52 -0700 +Subject: [PATCH] * src/pathx.c (parse_name): correctly handle trailing + whitespace in names + +When a name ended in whitespace, we incorrectly assumed it was always ok to +trim that whitespace. That is not true if that whitespace is escaped, +i.e. if the path expression is something like '/x\ '. In that case, the +name really needs to be literally 'x ', i.e., we can not trim that +whitespace. + +The incorrect behavior led to turning '/x\ ' first into 'x\' and then, +because we assume that '\' is always followed by a character inside the +string, when we removed the escaping '\', we would read beyond the end of +the intermediate string result; if we were lucky, that would lead to a +crash, otherwise we'd continue with junk. + +We now make sure that escaped whitespace at the end of a string does not +get stripped, avoiding all these headaches. + +Fixes RHBZ https://bugzilla.redhat.com/show_bug.cgi?id=1475621 +--- + src/pathx.c | 27 ++++++++++++++++----- + tests/test-xpath.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 80 insertions(+), 6 deletions(-) + +diff --git a/src/pathx.c b/src/pathx.c +index 8d8dbbbe..a726a032 100644 +--- a/src/pathx.c ++++ b/src/pathx.c +@@ -1643,6 +1643,16 @@ int pathx_escape_name(const char *in, char **out) { + return 0; + } + ++/* Return true if POS is preceded by an odd number of backslashes, i.e., if ++ * POS is escaped. Stop the search when we get to START */ ++static bool backslash_escaped(const char *pos, const char *start) { ++ bool result=false; ++ while (pos-- > start && *pos == '\\') { ++ result = !result; ++ } ++ return result; ++} ++ + /* + * NameNoWS ::= [^][|/\= \t\n] | \\. + * NameWS ::= [^][|/\=] | \\. +@@ -1652,11 +1662,14 @@ static char *parse_name(struct state *state) { + const char *s = state->pos; + char *result; + ++ /* Advance state->pos until it points to the first character that is ++ * not part of a name. */ + while (*state->pos != '\0' && strchr(name_follow, *state->pos) == NULL) { +- /* This is a hack: since we allow spaces in names, we need to avoid +- * gobbling up stuff that is in follow(Name), e.g. 'or' so that +- * things like [name1 or name2] still work. +- */ ++ /* Since we allow spaces in names, we need to avoid gobbling up ++ * stuff that is in follow(Name), e.g. 'or' so that things like ++ * [name1 or name2] still work. In other words, we'll parse 'x frob ++ * y' as one name, but for 'x or y', we consider 'x' a name in its ++ * own right. */ + if (STREQLEN(state->pos, " or ", strlen(" or ")) || + STREQLEN(state->pos, " and ", strlen(" and "))) + break; +@@ -1671,10 +1684,12 @@ static char *parse_name(struct state *state) { + state->pos += 1; + } + +- /* Strip trailing white space */ ++ /* Strip trailing white space. Make sure we respect escaped whitespace ++ * and don't strip it as in "x\\ " */ + if (state->pos > s) { + state->pos -= 1; +- while (isspace(*state->pos) && state->pos >= s) ++ while (isspace(*state->pos) && state->pos > s ++ && !backslash_escaped(state->pos, s)) + state->pos -= 1; + state->pos += 1; + } +diff --git a/tests/test-xpath.c b/tests/test-xpath.c +index 335e7bf8..dbba29e0 100644 +--- a/tests/test-xpath.c ++++ b/tests/test-xpath.c +@@ -331,6 +331,62 @@ static int test_wrong_regexp_flag(struct augeas *aug) { + return -1; + } + ++static int test_trailing_ws_in_name(struct augeas *aug) { ++ int r; ++ ++ printf("%-30s ... ", "trailing_ws_in_name"); ++ ++ /* We used to incorrectly lop escaped whitespace off the end of a ++ * name. Make sure that we really create a tree node with label 'x ' ++ * with the below set, and look for it in a number of ways to ensure we ++ * are not lopping off trailing whitespace. */ ++ r = aug_set(aug, "/ws\\ ", "1"); ++ if (r < 0) { ++ fprintf(stderr, "failed to set '/ws ': %d\n", r); ++ goto fail; ++ } ++ /* We did not create a node with label 'ws' */ ++ r = aug_get(aug, "/ws", NULL); ++ if (r != 0) { ++ fprintf(stderr, "created '/ws' instead: %d\n", r); ++ goto fail; ++ } ++ ++ /* We did not create a node with label 'ws\t' (this also checks that we ++ * don't create something like 'ws\\' by dropping the last whitespace ++ * character. */ ++ r = aug_get(aug, "/ws\\\t", NULL); ++ if (r != 0) { ++ fprintf(stderr, "found '/ws\\t': %d\n", r); ++ goto fail; ++ } ++ ++ /* But we did create 'ws ' */ ++ r = aug_get(aug, "/ws\\ ", NULL); ++ if (r != 1) { ++ fprintf(stderr, "could not find '/ws ': %d\n", r); ++ goto fail; ++ } ++ ++ /* If the whitespace is preceded by an even number of '\\' chars, ++ * whitespace must be stripped */ ++ r = aug_set(aug, "/nows\\\\ ", "1"); ++ if (r < 0) { ++ fprintf(stderr, "set of '/nows' failed: %d\n", r); ++ goto fail; ++ } ++ r = aug_get(aug, "/nows\\\\", NULL); ++ if (r != 1) { ++ fprintf(stderr, "could not get '/nows\\'\n"); ++ goto fail; ++ } ++ printf("PASS\n"); ++ return 0; ++ fail: ++ printf("FAIL\n"); ++ return -1; ++} ++ + static int run_tests(struct test *tests, int argc, char **argv) { + char *lensdir; + struct augeas *aug = NULL; +@@ -374,6 +430,9 @@ static int run_tests(struct test *tests, int argc, char **argv) { + + if (test_wrong_regexp_flag(aug) < 0) + result = EXIT_FAILURE; ++ ++ if (test_trailing_ws_in_name(aug) < 0) ++ result = EXIT_FAILURE; + } + aug_close(aug); + +-- +2.17.2 + diff --git a/SOURCES/0012-tests-test-save.c-testSaveNoPermission-skip-when-roo.patch b/SOURCES/0012-tests-test-save.c-testSaveNoPermission-skip-when-roo.patch new file mode 100644 index 0000000..85d9a56 --- /dev/null +++ b/SOURCES/0012-tests-test-save.c-testSaveNoPermission-skip-when-roo.patch @@ -0,0 +1,28 @@ +From f0e1dfad1c8a7c8193f2805c0919d6105344dc17 Mon Sep 17 00:00:00 2001 +From: Dominic Cleal +Date: Thu, 17 Dec 2015 10:40:45 +0000 +Subject: [PATCH] * tests/test-save.c (testSaveNoPermission): skip when root + +--- + tests/test-save.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/tests/test-save.c b/tests/test-save.c +index 4b6470f2..8775ba54 100644 +--- a/tests/test-save.c ++++ b/tests/test-save.c +@@ -355,6 +355,11 @@ static void testPathEscaping(CuTest *tc) { + * used to lead to a SEGV + */ + static void testSaveNoPermission(CuTest *tc) { ++ if (getuid() == 0) { ++ puts("pending (testSaveNoPermission): can't test permissions under root account"); ++ return; ++ } ++ + int r; + char *path = NULL; + const char *v; +-- +2.17.2 + diff --git a/SOURCES/0013-Chrony-allow-signed-numbers.patch b/SOURCES/0013-Chrony-allow-signed-numbers.patch new file mode 100644 index 0000000..c5f323f --- /dev/null +++ b/SOURCES/0013-Chrony-allow-signed-numbers.patch @@ -0,0 +1,52 @@ +From deae1ee7eafff09b983ba7b9bcb7e59df92a5cea Mon Sep 17 00:00:00 2001 +From: Miroslav Lichvar +Date: Wed, 3 Jun 2015 17:31:07 +0200 +Subject: [PATCH] Chrony: allow signed numbers + +--- + lenses/chrony.aug | 4 ++-- + lenses/tests/test_chrony.aug | 4 ++-- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/lenses/chrony.aug b/lenses/chrony.aug +index 32575688..5e30ee1f 100644 +--- a/lenses/chrony.aug ++++ b/lenses/chrony.aug +@@ -50,10 +50,10 @@ module Chrony = + let word = Rx.word + + (* Variable: integer *) +- let integer = Rx.integer ++ let integer = Rx.relinteger + + (* Variable: decimal *) +- let decimal = Rx.decimal ++ let decimal = Rx.reldecimal + + (* Variable: ip *) + let ip = Rx.ip +diff --git a/lenses/tests/test_chrony.aug b/lenses/tests/test_chrony.aug +index c4b552eb..905ecee4 100644 +--- a/lenses/tests/test_chrony.aug ++++ b/lenses/tests/test_chrony.aug +@@ -25,7 +25,7 @@ peer ntpc1.example.com + stratumweight 0 + driftfile /var/lib/chrony/drift + rtcsync +-makestep 10 3 ++makestep 10 -1 + bindcmdaddress 127.0.0.1 + bindcmdaddress ::1 + local stratum 10 +@@ -87,7 +87,7 @@ initstepslew 30 foo.bar.com baz.quz.com + { "rtcsync" } + { "makestep" + { "threshold" = "10" } +- { "limit" = "3" } ++ { "limit" = "-1" } + } + { "bindcmdaddress" = "127.0.0.1" } + { "bindcmdaddress" = "::1" } +-- +2.17.2 + diff --git a/SOURCES/0014-Fix-430-support-Krb5-include-dir.patch b/SOURCES/0014-Fix-430-support-Krb5-include-dir.patch new file mode 100644 index 0000000..9b4e4d3 --- /dev/null +++ b/SOURCES/0014-Fix-430-support-Krb5-include-dir.patch @@ -0,0 +1,52 @@ +From 430f0210d36d3abf2bfbe2a336f8f8d260ccc81b Mon Sep 17 00:00:00 2001 +From: "Jason A. Smith" +Date: Fri, 23 Dec 2016 03:19:24 -0500 +Subject: [PATCH] Fix #430 - support Krb5 include(dir)? + +Updated the Krb5 lens to support the include(dir)? directives, +with test case. +--- + lenses/krb5.aug | 9 +++++++-- + lenses/tests/test_krb5.aug | 9 +++++++++ + 2 files changed, 16 insertions(+), 2 deletions(-) + +diff --git a/lenses/krb5.aug b/lenses/krb5.aug +index 37778fd8..8936f3a0 100644 +--- a/lenses/krb5.aug ++++ b/lenses/krb5.aug +@@ -151,8 +151,13 @@ let kdc = + let pam = + simple_section "pam" name_re + +-let lns = (comment|empty)* . ++let includes = Build.key_value_line /include(dir)?/ Sep.space (store Rx.fspath) ++ ++let lns = (comment|empty|includes)* . + (libdefaults|login|appdefaults|realms|domain_realm + |logging|capaths|dbdefaults|dbmodules|instance_mapping|kdc|pam)* + +-let xfm = transform lns (incl "/etc/krb5.conf") ++let filter = (incl "/etc/krb5.conf.d/*.conf") ++ . (incl "/etc/krb5.conf") ++ ++let xfm = transform lns filter +diff --git a/lenses/tests/test_krb5.aug b/lenses/tests/test_krb5.aug +index e17a659a..743bb375 100644 +--- a/lenses/tests/test_krb5.aug ++++ b/lenses/tests/test_krb5.aug +@@ -1020,3 +1020,12 @@ default_ccache_name = KEYRING:persistent:%{uid}\n" = + { "libdefaults" + { } + { "default_ccache_name" = "KEYRING:persistent:%{uid}" } } ++ ++(* Include(dir) test *) ++let include_test = "include /etc/krb5.other_conf.d/other.conf ++includedir /etc/krb5.conf.d/ ++" ++ ++test Krb5.lns get include_test = ++ { "include" = "/etc/krb5.other_conf.d/other.conf" } ++ { "includedir" = "/etc/krb5.conf.d/" } +-- +2.17.2 + diff --git a/SOURCES/0015-Cgconfig-allow-fperm-dperm-in-admin-task.patch b/SOURCES/0015-Cgconfig-allow-fperm-dperm-in-admin-task.patch new file mode 100644 index 0000000..720905a --- /dev/null +++ b/SOURCES/0015-Cgconfig-allow-fperm-dperm-in-admin-task.patch @@ -0,0 +1,81 @@ +From de01f104d6ee4b11122aa4a108fc6082d3061886 Mon Sep 17 00:00:00 2001 +From: Pino Toscano +Date: Mon, 4 Sep 2017 18:45:05 +0200 +Subject: [PATCH] Cgconfig: allow fperm & dperm in admin & task + +These keys are used to control the permissions for files and +directories. +--- + lenses/cgconfig.aug | 2 +- + lenses/tests/test_cgconfig.aug | 45 ++++++++++++++++++++++++++++++++++ + 2 files changed, 46 insertions(+), 1 deletion(-) + +diff --git a/lenses/cgconfig.aug b/lenses/cgconfig.aug +index 6a5b8603..e766343d 100644 +--- a/lenses/cgconfig.aug ++++ b/lenses/cgconfig.aug +@@ -30,7 +30,7 @@ module Cgconfig = + let name = /[^#= \n\t{}\/]+/ + let cont_name = /(cpuacct|cpu|devices|ns|cpuset|memory|freezer|net_cls|blkio|hugetlb|perf_event)/ + let role_name = /(admin|task)/ +- let id_name = /(uid|gid)/ ++ let id_name = /(uid|gid|fperm|dperm)/ + let address = /[^#; \n\t{}]+/ + let qaddress = address|/"[^#;"\n\t{}]+"/ + +diff --git a/lenses/tests/test_cgconfig.aug b/lenses/tests/test_cgconfig.aug +index 6cd0856d..84fd2ded 100644 +--- a/lenses/tests/test_cgconfig.aug ++++ b/lenses/tests/test_cgconfig.aug +@@ -318,3 +318,48 @@ test Cgconfig.lns get group6 = + { } + } + ++let group7 =" ++group daemons/www { ++ perm { ++ task { ++ uid = root; ++ gid = root; ++ fperm = 770; ++ } ++ admin { ++ uid = root; ++ gid = root; ++ dperm = 777; ++ } ++ } ++} ++" ++ ++test Cgconfig.lns get group7 = ++ { } ++ { "group" = "daemons/www" ++ { } ++ { "perm" ++ { } ++ { "task" ++ { } ++ { "uid" = "root" } ++ { } ++ { "gid" = "root" } ++ { } ++ { "fperm" = "770" } ++ { } } ++ { } ++ { "admin" ++ { } ++ { "uid" = "root" } ++ { } ++ { "gid" = "root" } ++ { } ++ { "dperm" = "777" } ++ { } } ++ { } } ++ { } ++ } ++ { } ++ +-- +2.17.2 + diff --git a/SOURCES/0016-Grub-handle-top-level-boot-directive-494.patch b/SOURCES/0016-Grub-handle-top-level-boot-directive-494.patch new file mode 100644 index 0000000..dada3fd --- /dev/null +++ b/SOURCES/0016-Grub-handle-top-level-boot-directive-494.patch @@ -0,0 +1,55 @@ +From 06b3a79ee2bfdb4ae3675232e82ae3d06bbba353 Mon Sep 17 00:00:00 2001 +From: Pino Toscano +Date: Tue, 12 Sep 2017 10:58:46 +0200 +Subject: [PATCH] Grub: handle top-level "boot" directive (#494) + +Grub 1 effectively ignores commands in the configuration which work only +in the command line. The generated configuration by anaconda included +also a commented "boot=device" entry at the beginning: uncommenting that +does not make the configuration invalid, but makes the Grub lens not +able to parse it. + +Since there is no harm in representing a configuration key that will be +effectively ignored, accept top-level "boot" entries as well. +--- + lenses/grub.aug | 1 + + lenses/tests/test_grub.aug | 4 ++-- + 2 files changed, 3 insertions(+), 2 deletions(-) + +diff --git a/lenses/grub.aug b/lenses/grub.aug +index c52d16c6..9866f3f7 100644 +--- a/lenses/grub.aug ++++ b/lenses/grub.aug +@@ -148,6 +148,7 @@ module Grub = + | kw_menu_arg "foreground" + | kw_menu_arg "background" + | kw_menu_arg "verbose" ++ | kw_menu_arg "boot" (* only for CLI, ignored in conf *) + | serial + | terminal + | password_arg +diff --git a/lenses/tests/test_grub.aug b/lenses/tests/test_grub.aug +index f022ef72..8a0d9f4a 100644 +--- a/lenses/tests/test_grub.aug ++++ b/lenses/tests/test_grub.aug +@@ -8,7 +8,7 @@ module Test_grub = + # root (hd0,0) + # kernel /vmlinuz-version ro root=/dev/vg00/lv00 + # initrd /initrd-version.img +-#boot=/dev/sda ++boot=/dev/sda + device (hd0) HD(1,800,64000,9895c137-d4b2-4e3b-a93b-dc9ac4) + password --md5 $1$M9NLj$p2gs87vwNv48BUu.wAfVw0 + default=0 +@@ -53,7 +53,7 @@ title othermenu + { "#comment" = "root (hd0,0)" } + { "#comment" = "kernel /vmlinuz-version ro root=/dev/vg00/lv00" } + { "#comment" = "initrd /initrd-version.img" } +- { "#comment" = "boot=/dev/sda" } ++ { "boot" = "/dev/sda" } + { "device" = "(hd0)" + { "file" = "HD(1,800,64000,9895c137-d4b2-4e3b-a93b-dc9ac4)" } } + { "password" = "$1$M9NLj$p2gs87vwNv48BUu.wAfVw0" +-- +2.17.2 + diff --git a/SOURCES/0017-Fstab-allow-leading-whitespace-in-lines-with-spec-54.patch b/SOURCES/0017-Fstab-allow-leading-whitespace-in-lines-with-spec-54.patch new file mode 100644 index 0000000..608225c --- /dev/null +++ b/SOURCES/0017-Fstab-allow-leading-whitespace-in-lines-with-spec-54.patch @@ -0,0 +1,50 @@ +From 2565e67f724032cdc6217c2a2d2c1bc25ca23605 Mon Sep 17 00:00:00 2001 +From: Pino Toscano +Date: Tue, 13 Feb 2018 07:21:55 +0100 +Subject: [PATCH] Fstab: allow leading whitespace in lines with spec (#544) + +The documentation does not explicitly mention this possibility, but +tooling that parses fstab actually supports this: hence, allow leading +whitespace in lines with filesystem specification. +--- + lenses/fstab.aug | 1 + + lenses/tests/test_fstab.aug | 4 ++++ + 2 files changed, 5 insertions(+) + +diff --git a/lenses/fstab.aug b/lenses/fstab.aug +index bceaddd1..d67a3067 100644 +--- a/lenses/fstab.aug ++++ b/lenses/fstab.aug +@@ -23,6 +23,7 @@ module Fstab = + Build.opt_list lns comma + + let record = [ seq "mntent" . ++ Util.indent . + [ label "spec" . store spec ] . sep_tab . + [ label "file" . store file ] . sep_tab . + comma_sep_list "vfstype" . +diff --git a/lenses/tests/test_fstab.aug b/lenses/tests/test_fstab.aug +index fa044aea..438f619a 100644 +--- a/lenses/tests/test_fstab.aug ++++ b/lenses/tests/test_fstab.aug +@@ -11,6 +11,8 @@ module Test_fstab = + { "dump" = "1" } + { "passno" = "1" } } + ++ let leading_ws = " /dev/vg00/lv00\t /\t ext3\t defaults 1 1\n" ++ + let trailing_ws = "/dev/vg00/lv00\t /\t ext3\t defaults 1 1 \t\n" + + let gen_no_passno(passno:string) = +@@ -60,6 +62,8 @@ module Test_fstab = + + test Fstab.lns get simple = simple_tree + ++ test Fstab.lns get leading_ws = simple_tree ++ + test Fstab.lns get trailing_ws = simple_tree + + test Fstab.lns get no_passno = no_passno_tree +-- +2.17.2 + diff --git a/SOURCES/0018-Grub-tolerate-some-invalid-entries.patch b/SOURCES/0018-Grub-tolerate-some-invalid-entries.patch new file mode 100644 index 0000000..1e8643a --- /dev/null +++ b/SOURCES/0018-Grub-tolerate-some-invalid-entries.patch @@ -0,0 +1,159 @@ +From ccebad103f3466d5e8fc2b60f6127af618adf8d2 Mon Sep 17 00:00:00 2001 +From: David Lutterkort +Date: Mon, 4 Jun 2018 10:45:19 -0700 +Subject: [PATCH] Grub: tolerate some invalid entries + +Refusing to parse an entire file because of invalid entries is too +harsh. Try to make the behavior a little friendlier by simply mapping invalid +entries to '#error' nodes but still parsing the rest of the file. + +Also remove del_to_eol, that would delete anything up to eol; it was only +used in kw_pres, but should have never been used there. kw_pres should only +match the keyword and eol. A line like 'quiet foo bar baz' should not be +accepted by (kw_pres "quiet"). +--- + lenses/grub.aug | 58 ++++++++++++++++++++++++++++++++------ + lenses/tests/test_grub.aug | 25 ++++++++++++++++ + 2 files changed, 75 insertions(+), 8 deletions(-) + +diff --git a/lenses/grub.aug b/lenses/grub.aug +index 9866f3f7..f99a3a92 100644 +--- a/lenses/grub.aug ++++ b/lenses/grub.aug +@@ -29,9 +29,6 @@ module Grub = + (* View: eol *) + let eol = Util.eol + +- (* View: del_to_eol *) +- let del_to_eol = del /[^ \t\n]*/ "" +- + (* View: spc *) + let spc = Util.del_ws_spc + +@@ -92,7 +89,22 @@ module Grub = + eol ] + + (* View: kw_pres *) +- let kw_pres (kw:string) = [ opt_ws . key kw . del_to_eol . eol ] ++ let kw_pres (kw:string) = [ opt_ws . key kw . eol ] ++ ++ (* View: error ++ * Parse a line that looks almost like a valid setting, but isn't, ++ * into an '#error' node. Any line that starts with letters, but not ++ * anything matching kw, is considered an error line. ++ * ++ * Parameters: ++ * kw:regexp - the valid keywords that are _not_ considered an ++ * error ++ *) ++ let error (kw:regexp) = ++ let not_kw = /[a-zA-Z]+/ - kw in ++ [ label "#error" . Util.del_opt_ws "\t" ++ . store (not_kw . /([^a-zA-Z\n].*[^ \t\n])?/) . eol ] ++ + + (************************************************************************ + * Group: BOOT ENTRIES +@@ -138,8 +150,8 @@ module Grub = + spc . [ label "from" . store Rx.no_spaces ] )? . + eol ] + +- (* View: menu_setting *) +- let menu_setting = kw_menu_arg "default" ++ (* View: menu_entry *) ++ let menu_entry = kw_menu_arg "default" + | kw_menu_arg "fallback" + | kw_pres "hiddenmenu" + | kw_menu_arg "timeout" +@@ -156,6 +168,21 @@ module Grub = + | device + | setkey + ++ (* View: menu_error ++ * Accept lines not matching menu_entry and stuff them into ++ * '#error' nodes ++ *) ++ let menu_error = ++ let kw = /default|fallback|hiddenmenu|timeout|splashimage|gfxmenu/ ++ |/foreground|background|verbose|boot|password|title/ ++ |/serial|setkey|terminal|color|device/ in ++ error kw ++ ++ (* View: menu_setting ++ * a valid menu setting or a line that looks like one but is an #error ++ *) ++ let menu_setting = menu_entry | menu_error ++ + (* View: title *) + let title = del /title[ \t=]+/ "title " . value_to_eol . eol + +@@ -206,9 +233,9 @@ module Grub = + let configfile = + [ command "configfile" "\t" . spc . store Rx.no_spaces . eol ] + +- (* View: boot_setting ++ (* View: boot_entry + entries *) +- let boot_setting = ++ let boot_entry = + let boot_arg_re = "root" | "initrd" | "rootnoverify" | "uuid" + | "findroot" | "bootfs" (* Solaris extensions *) + in kw_boot_arg boot_arg_re +@@ -223,6 +250,21 @@ module Grub = + | kw_pres "makeactive" + | password_arg + ++ (* View: boot_error ++ * Accept lines not matching boot_entry and stuff them into ++ * '#error' nodes ++ *) ++ let boot_error = ++ let kw = /lock|uuid|password|root|initrd|rootnoverify|findroot|bootfs/ ++ |/configfile|chainloader|title|boot|quiet|kernel|module/ ++ |/makeactive|savedefault|map/ in ++ error kw ++ ++ (* View: boot_setting ++ * a valid boot setting or a line that looks like one but is an #error ++ *) ++ let boot_setting = boot_entry | boot_error ++ + (* View: boot *) + let boot = + let line = ((boot_setting|comment)* . boot_setting)? in +diff --git a/lenses/tests/test_grub.aug b/lenses/tests/test_grub.aug +index 8a0d9f4a..75657203 100644 +--- a/lenses/tests/test_grub.aug ++++ b/lenses/tests/test_grub.aug +@@ -257,3 +257,28 @@ password --encrypted ^9^32kwzzX./3WISQ0C /boot/grub/custom.lst + { "password" = "secret" + { "md5" } + } } ++ ++ (* Test parsing of invalid entries via menu_error *) ++ test Grub.lns get "default=0\ncrud=no\n" = ++ { "default" = "0" } ++ { "#error" = "crud=no" } ++ ++ (* We handle some pretty bizarre bad syntax *) ++ test Grub.lns get "default=0 ++crud no ++valid:nope ++nonsense = yes ++bad arg1 arg2 arg3=v\n" = ++ { "default" = "0" } ++ { "#error" = "crud no" } ++ { "#error" = "valid:nope" } ++ { "#error" = "nonsense = yes" } ++ { "#error" = "bad arg1 arg2 arg3=v" } ++ ++ (* Test parsing of invalid entries via boot_error *) ++ test Grub.lns get "title test ++ root (hd0,0) ++ crud foo\n" = ++ { "title" = "test" ++ { "root" = "(hd0,0)" } ++ { "#error" = "crud foo" } } +-- +2.17.2 + diff --git a/SOURCES/0019-Fix-sudoers-lens-always_query_group_plugin-588.patch b/SOURCES/0019-Fix-sudoers-lens-always_query_group_plugin-588.patch new file mode 100644 index 0000000..cbdf317 --- /dev/null +++ b/SOURCES/0019-Fix-sudoers-lens-always_query_group_plugin-588.patch @@ -0,0 +1,26 @@ +From 4e8c541392486f14715c5ec05da4612fc2e26ad9 Mon Sep 17 00:00:00 2001 +From: Steve Traylen +Date: Thu, 1 Nov 2018 13:54:32 +0100 +Subject: [PATCH] Fix sudoers lens: "always_query_group_plugin" (#588) + +The option is now enabled by default in the default sudoers of +RHEL 7.6 (and probably soon CentOS 7). +--- + lenses/sudoers.aug | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/lenses/sudoers.aug b/lenses/sudoers.aug +index 0437daae..d6140a8b 100644 +--- a/lenses/sudoers.aug ++++ b/lenses/sudoers.aug +@@ -308,6 +308,7 @@ let parameter_flag_kw = "always_set_home" | "authenticate" | "env_editor" + | "closefrom_override" | "compress_io" | "fast_glob" + | "log_input" | "log_output" | "pwfeedback" + | "umask_override" | "use_pty" | "match_group_by_gid" ++ | "always_query_group_plugin" + + let parameter_flag = [ del_negate . negate_node? + . key parameter_flag_kw ] +-- +2.17.2 + diff --git a/SOURCES/0020-New-lens-Anaconda-597.patch b/SOURCES/0020-New-lens-Anaconda-597.patch new file mode 100644 index 0000000..cd78b63 --- /dev/null +++ b/SOURCES/0020-New-lens-Anaconda-597.patch @@ -0,0 +1,186 @@ +From ba333a3205324a7b0489d93b67317c72b76fe8bf Mon Sep 17 00:00:00 2001 +From: Pino Toscano +Date: Wed, 12 Dec 2018 13:54:06 +0100 +Subject: [PATCH] New lens: Anaconda (#597) + +Introduce a new lens to parse the INI-like `/etc/sysconfig/anaconda` instead of using `Shellvars`. +--- + lenses/anaconda.aug | 30 +++++++++++ + lenses/shellvars.aug | 1 + + lenses/tests/test_anaconda.aug | 89 +++++++++++++++++++++++++++++++ + tests/Makefile.am | 1 + + tests/root/etc/sysconfig/anaconda | 5 ++ + 5 files changed, 126 insertions(+) + create mode 100644 lenses/anaconda.aug + create mode 100644 lenses/tests/test_anaconda.aug + create mode 100644 tests/root/etc/sysconfig/anaconda + +diff --git a/lenses/anaconda.aug b/lenses/anaconda.aug +new file mode 100644 +index 00000000..8f618db2 +--- /dev/null ++++ b/lenses/anaconda.aug +@@ -0,0 +1,30 @@ ++(* ++Module: Anaconda ++ Parses Anaconda's user interaction configuration files. ++ ++Author: Pino Toscano ++ ++About: Reference ++ https://anaconda-installer.readthedocs.io/en/latest/user-interaction-config-file-spec.html ++ ++About: Configuration file ++ This lens applies to /etc/sysconfig/anaconda. ++ ++About: License ++ This file is licensed under the LGPL v2+, like the rest of Augeas. ++*) ++module Anaconda = ++autoload xfm ++ ++let comment = IniFile.comment "#" "#" ++let sep = IniFile.sep "=" "=" ++ ++let entry = IniFile.entry IniFile.entry_re sep comment ++let title = IniFile.title IniFile.record_re ++let record = IniFile.record title entry ++ ++let lns = IniFile.lns record comment ++ ++let filter = incl "/etc/sysconfig/anaconda" ++ ++let xfm = transform lns filter +diff --git a/lenses/shellvars.aug b/lenses/shellvars.aug +index 25bb82b9..03ab921b 100644 +--- a/lenses/shellvars.aug ++++ b/lenses/shellvars.aug +@@ -198,6 +198,7 @@ module Shellvars = + + let filter_sysconfig = + sc_incl "*" . ++ sc_excl "anaconda" . + sc_excl "bootloader" . + sc_excl "hw-uuid" . + sc_excl "hwconf" . +diff --git a/lenses/tests/test_anaconda.aug b/lenses/tests/test_anaconda.aug +new file mode 100644 +index 00000000..50b0ac22 +--- /dev/null ++++ b/lenses/tests/test_anaconda.aug +@@ -0,0 +1,89 @@ ++(* ++Module: Test_Anaconda ++ Provides unit tests and examples for the lens. ++ ++ - 'exampleN' snippets are taken from the documentation: ++ https://anaconda-installer.readthedocs.io/en/latest/user-interaction-config-file-spec.html ++ - 'installedN' snippets are taken from the resulting files after ++ a successful installation ++*) ++ ++module Test_Anaconda = ++ ++let example1 = "# comment example - before the section headers ++ ++[section_1] ++# comment example - inside section 1 ++key_a_in_section1=some_value ++key_b_in_section1=some_value ++ ++[section_2] ++# comment example - inside section 2 ++key_a_in_section2=some_value ++" ++ ++test Anaconda.lns get example1 = ++ { "#comment" = "comment example - before the section headers" } ++ { } ++ { "section_1" ++ { "#comment" = "comment example - inside section 1" } ++ { "key_a_in_section1" = "some_value" } ++ { "key_b_in_section1" = "some_value" } ++ { } ++ } ++ { "section_2" ++ { "#comment" = "comment example - inside section 2" } ++ { "key_a_in_section2" = "some_value" } ++ } ++ ++let example2 = "# this is the user interaction config file ++ ++[General] ++post_install_tools_disabled=0 ++ ++[DatetimeSpoke] ++# the date and time spoke has been visited ++visited=1 ++changed_timezone=1 ++changed_ntp=0 ++changed_timedate=1 ++ ++[KeyboardSpoke] ++# the keyboard spoke has not been visited ++visited=0 ++" ++ ++test Anaconda.lns get example2 = ++ { "#comment" = "this is the user interaction config file" } ++ { } ++ { "General" ++ { "post_install_tools_disabled" = "0" } ++ { } ++ } ++ { "DatetimeSpoke" ++ { "#comment" = "the date and time spoke has been visited" } ++ { "visited" = "1" } ++ { "changed_timezone" = "1" } ++ { "changed_ntp" = "0" } ++ { "changed_timedate" = "1" } ++ { } ++ } ++ { "KeyboardSpoke" ++ { "#comment" = "the keyboard spoke has not been visited" } ++ { "visited" = "0" } ++ } ++ ++let installed1 = "# This file has been generated by the Anaconda Installer 21.48.22.134-1 ++ ++[ProgressSpoke] ++visited = 1 ++ ++" ++ ++test Anaconda.lns get installed1 = ++ { "#comment" = "This file has been generated by the Anaconda Installer 21.48.22.134-1" } ++ { } ++ { "ProgressSpoke" ++ { "visited" = "1" } ++ { } ++ } +diff --git a/tests/Makefile.am b/tests/Makefile.am +index 4d2b2605..08d5dc59 100644 +--- a/tests/Makefile.am ++++ b/tests/Makefile.am +@@ -22,6 +22,7 @@ lens_tests = \ + lens-activemq_xml.sh \ + lens-afs_cellalias.sh \ + lens-aliases.sh \ ++ lens-anaconda.sh \ + lens-anacron.sh \ + lens-approx.sh \ + lens-apt_update_manager.sh \ +diff --git a/tests/root/etc/sysconfig/anaconda b/tests/root/etc/sysconfig/anaconda +new file mode 100644 +index 00000000..73318cf6 +--- /dev/null ++++ b/tests/root/etc/sysconfig/anaconda +@@ -0,0 +1,5 @@ ++# This file has been generated by the Anaconda Installer 21.48.22.134-1 ++ ++[ProgressSpoke] ++visited = 1 ++ +-- +2.17.2 + diff --git a/SPECS/augeas.spec b/SPECS/augeas.spec new file mode 100644 index 0000000..20e3976 --- /dev/null +++ b/SPECS/augeas.spec @@ -0,0 +1,382 @@ +Name: augeas +Version: 1.4.0 +Release: 9%{?dist} +Summary: A library for changing configuration files + +Group: System Environment/Libraries +License: LGPLv2+ +URL: http://augeas.net/ +Source0: http://download.augeas.net/%{name}-%{version}.tar.gz +Patch1: 0001-Syslog-restored-Augeas-1.1.0-tree-compatibility-for-.patch +Patch2: 0002-Revert-Use-Quote-module-in-dovecot.patch +Patch3: 0003-Revert-Jaas-add-several-improvements-to-cover-more-v.patch +Patch4: 0004-UpdateDB-autoload-etc-updatedb.conf-with-Simplevars.patch +Patch5: 0005-Revert-Dnsmasq-add-structure-to-address-and-server-o.patch +Patch6: 0006-Sshd-revert-Sshd-module-to-1.1.0-compatible-add-Sshd.patch +Patch7: 0007-Dhcpd-revert-Dhcpd-module-to-1.1.0-compatible-add-Dh.patch +Patch8: 0008-Slapd-revert-Slapd-module-to-1.1.0-compatible-add-Sl.patch +Patch9: 0009-Rhsm-new-lens-to-parse-subscription-manager-s-rhsm.c.patch +Patch10: 0010-Fix-sudoers-lens-recognize-match_group_by_gid.patch +Patch11: 0011-src-pathx.c-parse_name-correctly-handle-trailing-whi.patch +Patch12: 0012-tests-test-save.c-testSaveNoPermission-skip-when-roo.patch +Patch13: 0013-Chrony-allow-signed-numbers.patch +Patch14: 0014-Fix-430-support-Krb5-include-dir.patch +Patch15: 0015-Cgconfig-allow-fperm-dperm-in-admin-task.patch +Patch16: 0016-Grub-handle-top-level-boot-directive-494.patch +Patch17: 0017-Fstab-allow-leading-whitespace-in-lines-with-spec-54.patch +Patch18: 0018-Grub-tolerate-some-invalid-entries.patch +Patch19: 0019-Fix-sudoers-lens-always_query_group_plugin-588.patch +Patch20: 0020-New-lens-Anaconda-597.patch + +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) + +BuildRequires: readline-devel libselinux-devel libxml2-devel +BuildRequires: autoconf, automake +Requires: %{name}-libs = %{version}-%{release} + +%description +A library for programmatically editing configuration files. Augeas parses +configuration files into a tree structure, which it exposes through its +public API. Changes made through the API are written back to the initially +read files. + +The transformation works very hard to preserve comments and formatting +details. It is controlled by ``lens'' definitions that describe the file +format and the transformation into a tree. + +This package attempts to be compatible with Augeas 1.1.0 as shipped in +EL7.0, where possible. + +%package devel +Summary: Development files for %{name} +Group: Development/Libraries +Requires: %{name}-libs = %{version}-%{release} +Requires: pkgconfig + +%description devel +The %{name}-devel package contains libraries and header files for +developing applications that use %{name}. + + +%package libs +Summary: Libraries for %{name} +Group: System Environment/Libraries + +Provides: bundled(gnulib) + +%description libs +The libraries for %{name}. + + +%prep +%setup -q +%patch1 -p1 +%patch2 -p1 +%patch3 -p1 +%patch4 -p1 +%patch5 -p1 +%patch6 -p1 +%patch7 -p1 +%patch8 -p1 +%patch9 -p1 +%patch10 -p1 +%patch11 -p1 +%patch12 -p1 +%patch13 -p1 +%patch14 -p1 +%patch15 -p1 +%patch16 -p1 +%patch17 -p1 +%patch18 -p1 +%patch19 -p1 +%patch20 -p1 + +# Patches affect Makefile.am and configure.ac, so rerun autotools. +autoreconf +autoconf + +%build +%configure --disable-static +make %{?_smp_mflags} + +%check +# Disable test-preserve.sh SELinux testing. This fails when run under mock due +# to differing SELinux labelling. +export SKIP_TEST_PRESERVE_SELINUX=1 + +make %{?_smp_mflags} check || { + echo '===== tests/test-suite.log =====' + cat tests/test-suite.log + exit 1 +} + +%install +rm -rf $RPM_BUILD_ROOT +make install DESTDIR=$RPM_BUILD_ROOT INSTALL="%{__install} -p" +find $RPM_BUILD_ROOT -name '*.la' -exec rm -f {} ';' + +# The tests/ subdirectory contains lenses used only for testing, and +# so it shouldn't be packaged. +rm -r $RPM_BUILD_ROOT%{_datadir}/augeas/lenses/dist/tests + +%clean +rm -rf $RPM_BUILD_ROOT + +%post libs -p /sbin/ldconfig + +%postun libs -p /sbin/ldconfig + +%files +%defattr(-,root,root,-) +%{_bindir}/augtool +%{_bindir}/augparse +%{_bindir}/fadot +%doc %{_mandir}/man1/* +%{_datadir}/vim/vimfiles/syntax/augeas.vim +%{_datadir}/vim/vimfiles/ftdetect/augeas.vim + +%files libs +%defattr(-,root,root,-) +# %{_datadir}/augeas and %{_datadir}/augeas/lenses are owned +# by filesystem. +%{_datadir}/augeas/lenses/dist +%{_libdir}/*.so.* +%doc AUTHORS COPYING NEWS + +%files devel +%defattr(-,root,root,-) +%doc +%{_includedir}/* +%{_libdir}/*.so +%{_libdir}/pkgconfig/augeas.pc + +%changelog +* Wed Dec 19 2018 Pino Toscano - 1.4.0-9 +- Add "Provides: bundled(gnulib)" to augeas-libs, as it embeds gnulib + (RHBZ#1653766) +- Anaconda: new lens (RHBZ#1657189) + +* Tue Nov 13 2018 Pino Toscano - 1.4.0-8 +- Sudoers: handle "always_query_group_plugin" option (RHBZ#1649287) + +* Tue Nov 13 2018 Pino Toscano - 1.4.0-7 +- Grub: better handle invalid grub.conf files (RHBZ#1582236) + +* Thu Mar 29 2018 Pino Toscano - 1.4.0-6 +- Fstab: allow leading whitespaces (RHBZ#1544520) + +* Wed Oct 04 2017 Pino Toscano - 1.4.0-5 +- Cgconfig: allow fperm & dperm in admin & task (RHBZ#1325741) +- Grub: handle top-level "boot" directive (RHBZ#1484261) + +* Mon Sep 04 2017 Pino Toscano - 1.4.0-4 +- Fix CVE-2017-7555, improper handling of escaped strings (RHBZ#1481546) +- Skip testSaveNoPermission when running as root (RHBZ#1269817) +- Chrony: allow signed numbers (RHBZ#1302017) +- Krb5: support includedir (RHBZ#1406111) + +* Tue Aug 29 2017 Luigi Toscano - 1.4.0-3 + Fix sudoers lens: recognize "match_group_by_gid" (RHBZ#1483888) + +* Thu Jul 30 2015 Dominic Cleal - 1.4.0-2 +- Rhsm: add to parse subscription-manager config (RHBZ#1141121) + +* Fri Jun 12 2015 Dominic Cleal - 1.4.0-1 +- Rebase to Augeas 1.4.0 +- Revert some changes for better compatibility with 1.1.0-17: + * Dhcpd: keep 1.1.0 behaviour, add Dhcpd_140 for 1.4.0 features + * Dnsmasq: revert splitting of address/server options + * Dovecot: restore quotes within values + * Jaas: revert semicolon and line break changes + * Slapd: keep 1.1.0 behaviour, add Slapd_140 for 1.4.0 features + * Sshd: keep 1.1.0 behaviour, add Sshd_140 for 1.4.0 features + * Syslog: restore tree without protocol for UDP hosts + * UpdateDB: keep Simplevars to load config by default + +* Thu Nov 27 2014 Dominic Cleal - 1.1.0-17 +- Device_map: parse all device.map files under /boot (RHBZ#1166582) + +* Tue Sep 23 2014 Dominic Cleal - 1.1.0-16 +- Iptables: parse /etc/sysconfig/iptables.save (RHBZ#1144651) +- Lvm: parse /etc/lvm/lvm.conf (RHBZ#1145495) +- Shadow: add lens (RHBZ#1145249) + +* Thu Sep 18 2014 Dominic Cleal - 1.1.0-15 +- Remove man/augtool.1 patches, always create .1 during build (RHBZ#1143954) + +* Thu Sep 18 2014 Dominic Cleal - 1.1.0-14 +- Kdump: parse new options, EOL comments (RHBZ#1139298) +- Rsyslog: parse property filters and templates (RHBZ#1138402) +- Systemd: parse semicolons inside entry values (RHBZ#1139498) +- Systemd: parse environment variables where value is quoted (RHBZ#1138508) + +* Thu Sep 04 2014 Dominic Cleal - 1.1.0-13 +- aug_save: return error when unlink fails (RHBZ#1091143) +- augtool: add aliases to autocomplete (RHBZ#1100076) +- augtool: remove unused dump-xml arg (RHBZ#1100106) +- Automounter: parse hostnames with hyphens (RHBZ#1075162) +- Cgconfig: parse other valid controllers (RHBZ#1112543) +- Chrony: add lens (RHBZ#1071947) +- docs: update man page with new commands (RHBZ#1100077) +- Exports: permit colons for IPv6 client addresses (RHBZ#1067030) +- Httpd: parse continued, quoted lines (RHBZ#1100551) +- Ldso: parse hwcap lines (RHBZ#1102629) +- NagiosCfg: parse nrpe.cfg with Nrpe (RHBZ#1102623) +- Rmt: add lens (RHBZ#1100549) +- Services: permit colons in service name (RHBZ#1121527) +- Shellvars: support arithmetic expansion (RHBZ#1100550) +- Syslog: parse TCP loghosts (RHBZ#1129386) +- Syslog: parse IPv6 loghost addresses (RHBZ#1129388) +- Systemd: parse /etc/sysconfig/*.systemd (RHBZ#1083022) +- Systemd: parse quoted environment vars (RHBZ#1100547) + +* Tue Feb 25 2014 Dominic Cleal - 1.1.0-12 +- Add patch for Dovecot, mailbox and quote support (RHBZ#1064387) +- Add patch for Keepalived, virtual server fixes (RHBZ#1064388) +- Add patch for Krb5, parse braces in values (RHBZ#1066419) + +* Thu Feb 20 2014 Dominic Cleal - 1.1.0-11 +- Add patch for Yum, split exclude lines (RHBZ#1067039) + +* Tue Feb 18 2014 Dominic Cleal - 1.1.0-10 +- Add patch for IPRoute2, hex and hyphen protocols (RHBZ#1063961) +- Add patch for IPRoute2, slashes in protocols (RHBZ#1063968) + +* Mon Feb 10 2014 Dominic Cleal - 1.1.0-9 +- Add patch for yum-cron.conf incl entry (RHBZ#1058409) +- Add patch for firewalld.conf incl entry (RHBZ#1058411) +- Add patch for Grub, foreground option (RHBZ#1059426) +- Add patch for Yum, spaces around equals (RHBZ#1062614) +- Add patch for Shellvars, case and same-line ;; (RHBZ#1056541) + +* Fri Jan 24 2014 Daniel Mach - 1.1.0-8 +- Mass rebuild 2014-01-24 + +* Tue Jan 14 2014 Dominic Cleal - 1.1.0-7 +- Fix CVE-2013-6412, incorrect permissions under strict umask (RHBZ#1036081) + +* Thu Jan 02 2014 Dominic Cleal - 1.1.0-6 +- Add patch for Sysconfig module, empty comment lines (RHBZ#1043665) +- Add check section to run test suite +- Add patch for testPermsErrorReported test, when root (RHBZ#1043666) +- Add patch for Shellvars, multivariable exports (RHBZ#1043815) + +* Fri Dec 27 2013 Daniel Mach - 1.1.0-5 +- Mass rebuild 2013-12-27 + +* Tue Nov 19 2013 Dominic Cleal - 1.1.0-4 +- Add patch for saving files with // in incl path (RHBZ#1031084) + +* Tue Oct 22 2013 Dominic Cleal - 1.1.0-3 +- Add patch for Grub module, setkey/lock support (RHBZ#1019485) + +* Mon Aug 12 2013 Dominic Cleal - 1.1.0-2 +- Fix source URL to download.augeas.net (RHBZ#996033) + +* Wed Jun 19 2013 David Lutterkort - 1.1.0-1 +- Update to 1.1.0; remove all patches + +* Tue Jun 18 2013 Richard W.M. Jones - 1.0.0-4 +- Fix /etc/sysconfig/network (RHBZ#904222). + +* Wed Jun 5 2013 Richard W.M. Jones - 1.0.0-3 +- Don't package lenses in tests/ subdirectory. + +* Wed Feb 13 2013 Fedora Release Engineering - 1.0.0-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild + +* Fri Jan 4 2013 David Lutterkort - 1.0.0-1 +- New version; remove all patches + +* Wed Jul 18 2012 Fedora Release Engineering - 0.10.0-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Tue Jan 10 2012 David Lutterkort - 0.10.0-3 +- Add patches for bugs 247 and 248 (JSON lens) + +* Sat Dec 3 2011 Richard W.M. Jones - 0.10.0-2 +- Add patch to resolve missing libxml2 requirement in augeas.pc. + +* Fri Dec 2 2011 David Lutterkort - 0.10.0-1 +- New version + +* Mon Jul 25 2011 David Lutterkort - 0.9.0-1 +- New version; removed patch pathx-whitespace-ea010d8 + +* Tue May 3 2011 David Lutterkort - 0.8.1-2 +- Add patch pathx-whitespace-ea010d8.patch to fix BZ 700608 + +* Fri Apr 15 2011 David Lutterkort - 0.8.1-1 +- New version + +* Wed Feb 23 2011 David Lutterkort - 0.8.0-1 +- New version + +* Mon Feb 07 2011 Fedora Release Engineering - 0.7.4-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild + +* Mon Nov 22 2010 Matthew Booth - 0.7.4-1 +- Update to version 0.7.4 + +* Thu Nov 18 2010 Richard W.M. Jones - 0.7.3-2 +- Upstream patch proposed to fix GCC optimization bug (RHBZ#651992). + +* Fri Aug 6 2010 David Lutterkort - 0.7.3-1 +- Remove upstream patches + +* Tue Jun 29 2010 David Lutterkort - 0.7.2-2 +- Patches based on upstream fix for BZ 600141 + +* Tue Jun 22 2010 David Lutterkort - 0.7.2-1 +- Fix ownership of /usr/share/augeas. BZ 569393 + +* Wed Apr 21 2010 David Lutterkort - 0.7.1-1 +- New version + +* Thu Jan 14 2010 David Lutterkort - 0.7.0-1 +- Remove patch vim-ftdetect-syntax.patch. It's upstream + +* Tue Dec 15 2009 David Lutterkort - 0.6.0-2 +- Fix ftdetect file for vim + +* Mon Nov 30 2009 David Lutterkort - 0.6.0-1 +- Install vim syntax files + +* Mon Sep 14 2009 David Lutterkort - 0.5.3-1 +- Remove separate xorg.aug, included in upstream source + +* Tue Aug 25 2009 Matthew Booth - 0.5.2-3 +- Include new xorg lens from upstream + +* Fri Jul 24 2009 Fedora Release Engineering - 0.5.2-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild + +* Mon Jul 13 2009 David Lutterkort - 0.5.2-1 +- New version + +* Fri Jun 5 2009 David Lutterkort - 0.5.1-1 +- Install fadot + +* Fri Mar 27 2009 David Lutterkort - 0.5.0-2 +- fadot isn't being installed just yet + +* Tue Mar 24 2009 David Lutterkort - 0.5.0-1 +- New program /usr/bin/fadot + +* Mon Mar 9 2009 David Lutterkort - 0.4.2-1 +- New version + +* Fri Feb 27 2009 David Lutterkort - 0.4.1-1 +- New version + +* Fri Feb 6 2009 David Lutterkort - 0.4.0-1 +- New version + +* Mon Jan 26 2009 David Lutterkort - 0.3.6-1 +- New version + +* Tue Dec 23 2008 David Lutterkort - 0.3.5-1 +- New version + +* Mon Feb 25 2008 David Lutterkort - 0.0.4-1 +- Initial specfile