[sudo-workers] [PATCH] sudo/plugins/suoders/sudoers2ldif: Support #include and #includedir recursively

Natale Vinto nvinto at redhat.com
Mon Oct 16 08:11:03 MDT 2017


Hello,

as said sometimes ago in the mailing list, I was wondering on how
better extend sudoers2ldif script, starting from supporting #include
and #includedir.

The idea is to look recursively for any #include and #includedir
directive in file parsed, and then parse it accordingly maintaining
the same behavior as now.

Thanks to dakkar [1], I could implement it through a callbacks
mechanism as shown in the proposed patch below.

What do you think?

Thanks,
Natale

[1] http://search.cpan.org/~dakkar/

diff -pru  a/sudo/plugins/sudoers/sudoers2ldif
b/sudo/plugins/sudoers/sudoers2ldif

--- sudoers2ldif2 2017-10-11 12:10:13.603919900 +0200
+++ sudoers2ldif 2017-10-16 16:07:05.540025799 +0200
@@ -46,27 +46,31 @@ my $did_defaults=0;
 my $order = 0;
 my %seen_users;

-# parse sudoers one line at a time
-while (<>){

-  # remove comment
-  s/#.*//;

-  # line continuation
-  $_.=<> while s/\\\s*$//s;

+# Parsing is now through callbacks reading @ARGV or STDIN
+sub parse_sudoers_line{
+
+  my $line = shift;
+  # remove comment
+  $line =~ s/#.*//;
+
+
   # cleanup newline
-  chomp;
+  chomp $line;
+
+
+  return if $line =~ /^\s*$/;

-  # ignore blank lines
-  next if /^\s*$/;

-  if (s/^Defaults\s+//) {
-    s/\s+$//; # remove trailing whitespace
+  if ($line =~ s/^Defaults\s+//) {
+
+    $line =~ s/\s+$//; # remove trailing whitespace
     # remove spaces between '!', '=', '+=' and '-='
-    s/^(\S+)\s*([\+-]?=)\s*(\S.*)$/$1$2$3/ unless s/^!\s*(\S.*)$/!$1/;
-    push @options, $_;
-  } elsif (/^(\S+)\s+([^=]+)=\s*(.*)/) {
+    $line =~ s/^(\S+)\s*([\+-]?=)\s*(\S.*)$/$1$2$3/ unless $line =~
s/^!\s*(\S.*)$/!$1/;
+    push @options, $line;
+  } elsif ($line =~ /^(\S+)\s+([^=]+)=\s*(.*)/) {
     # Aliases or Definitions
     my ($p1,$p2,$p3)=($1,$2,$3);
     $p2=~s/\s+$//; # remove trailing whitespace
@@ -132,7 +136,7 @@ while (<>){
       print "\n";
     }
   } else {
-    print "parse error: $_\n";
+    print STDERR "parse error: $line\n";
   }
 }

@@ -172,3 +176,70 @@ sub expand{
   push @a,$ref->{$_} ? expand($ref,split /\s*,\s*/,$ref->{$_}):$_ foreach @_;
   @a;
 }
+
+
+# Recursively look for #include and #includedir directives
+sub scan_sudoers_fh {
+    my ($filehandle,$callback) = @_;
+
+    while (<$filehandle>) {
+        if (/^#include\s+(.+?)\s*$/){
+            my $inc = $1;
+            scan_sudoers_filename($inc,$callback);
+        }
+        elsif (/^#includedir\s+(.+?)\s*$/){
+            my $incdir = $1;
+            scan_sudoers_dirname($incdir,$callback);
+        }
+        else {
+            $callback->($_);
+        }
+    }
+}
+
+# Read from #include file
+sub scan_sudoers_filename {
+    my ($filename,$callback) = @_;
+    open my $fh, '<', $filename;
+    scan_sudoers_fh($fh,$callback);
+}
+
+# Read from #includedir directory
+sub scan_sudoers_dirname {
+    my ($dirname,$callback) = @_;
+    # qui puoi filtrare via i file che sudo ignorerebbe
+    scan_sudoers_filename($_,$callback)
+        for glob("$dirname/*");
+}
+
+# Returns a sub that reads lines until continuations,
+# then it invokes the callback that parses
+sub make_continuation_handler {
+    my ($callback) = @_;
+
+    my $buffer='';
+    return sub {
+        my ($line) = @_;
+
+        if ($line =~ s/\\\s*$//) {
+            # line continuation
+            $buffer .= $line;
+        }
+        else {
+            # parse all
+            $callback->($buffer.$line);
+            # empty buffer
+            $buffer='';
+        }
+
+    };
+}
+
+
+my $parser_cb = make_continuation_handler(\&parse_sudoers_line);
+if (@ARGV) {
+    scan_sudoers_filename($_,$parser_cb) for @ARGV;
+}
+else {
+    scan_sudoers_fh(\*STDIN,$parser_cb);
+}


More information about the sudo-workers mailing list