[sf-perl] regex problem: append path only if not in list already
David Christensen
dpchrist at holgerdanske.com
Tue Mar 2 21:04:07 PST 2021
On 3/2/21 3:55 PM, Joseph Brenner wrote:
>> Indeed the "\s*" parts are not needed
>
> Yes, but that's more of a nit that anything. They don't cause any
> problems, either (and actually, I don't know the precise rules are
> about what you can encounter in these files).
sudoers(5) describes the syntax.
visudo(8) can check the syntax of the sudoers(5) file or the syntax of a
specified file.
Here is my script. It uses a loop to process the input one line at a
time, concatenates continued lines, uses a match regular expression to
split the desired lines into a front half (assignment expression) and a
back half (trailing white space and comment), and inserts the delimiter
and path component. I found that '[\\\s]+' and/or '[\\\s]*' were
required for white space and continued lines, non-greedy '.*?' was
required for the front half, and non-capturing parentheses and a newline
were required for the back half. I do not see how to convert this
solution into a substitution regular expression that could operate on
the contents of an entire sudoers(5) file as a string:
2021-03-02 20:41:32 dpchrist at tinkywinky
~/sandbox/perl/sudoers-secure_path-usr_local_bin
$ cat dpchrist.pl
#!perl
# $Id: dpchrist.pl,v 1.15 2021/03/03 04:26:36 dpchrist Exp $
# By David Paul Christensen dpchrist at holgerdanske.com
# Public Domain.
#
#
https://github.com/doomvox/raku-study/blob/main/bin/2021feb28/pcre_regex_to_append_path_non_redundantly.t
use strict;
use warnings;
use Data::Dumper;
use File::Basename;
use File::Slurp;
use Getopt::Long;
my $base = basename $0;
my $debug = undef;
my $visudo = '/usr/sbin/visudo';
sub _d { warn((caller(0))[2], $", Data::Dumper->Dump(@_)) if $debug }
GetOptions('debug|d' => \$debug)
or die "ERROR $base processing arguments";
die "Usage: $base [--debug|-d] FILE\n" unless @ARGV == 1;
my $file = shift;
my @in = read_file($file);
_d [\@in], [qw(*in)];
system $visudo, '-c', '-q', '-s', '-f', $file
and die "ERROR $base invalid sudoers(5) syntax '$file'";
my @out;
my $delimiter = ':';
my $newline = "\n";
my $comp = '/usr/local/bin';
my $rx =
qr(^(\s*Defaults[\\\s]+secure_path[\\\s]*=[\\\s]*.*?)((?:[\\\s]*#.*)?\n$))s;
for (my $i = 0; $i < @in; $i++) {
my $line = $in[$i];
_d [$i], [qw(i)]; _d [$line], [qw(line)];
while ($i < @in && $line =~ m{\\$}s) {
$line .= $in[++$i];
_d [$i], [qw(i)]; _d [$line], [qw(line)];
}
if ( $line !~ /$comp/s && $line =~ $rx) {
my $front = $1; _d [$front], [qw(front)];
my $back = $2; _d [$back ], [qw(back )];
push @out, $front . $delimiter . $comp . $back;
_d [$out[-1]], [qw(out)];
} else {
push @out, $line;
_d [$out[-1]], [qw(out)];
}
}
_d [\@out], [qw(*out)];
$file =~ s/\.in/.out.dpchrist/;
write_file($file, @out);
system $visudo, '-c', '-q', '-s', '-f', $file
and die "ERROR $base invalid sudoers(5) syntax '$file'";
Here is the default Debian sudoers(5) file (with the '#include'
statement disabled). It is syntactically correct, and already includes
the desired path component for 'secure_path'. When processed, the
output should match the input:
2021-03-02 19:25:38 dpchrist at tinkywinky
~/sandbox/perl/sudoers-secure_path-usr_local_bin
$ cat sudoers.0.in
#
# This file MUST be edited with the 'visudo' command as root.
#
# Please consider adding local content in /etc/sudoers.d/ instead of
# directly modifying this file.
#
# See the man page for details on how to write a sudoers file.
#
Defaults env_reset
Defaults mail_badpass
Defaults
secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
# Host alias specification
# User alias specification
# Cmnd alias specification
# User privilege specification
root ALL=(ALL:ALL) ALL
# Allow members of group sudo to execute any command
%sudo ALL=(ALL:ALL) ALL
# See sudoers(5) for more information on "#include" directives:
##includedir /etc/sudoers.d
2021-03-02 19:25:43 dpchrist at tinkywinky
~/sandbox/perl/sudoers-secure_path-usr_local_bin
$ /usr/sbin/visudo -c -s -f sudoers.0.in
sudoers.0.in: parsed OK
2021-03-02 19:25:57 dpchrist at tinkywinky
~/sandbox/perl/sudoers-secure_path-usr_local_bin
$ perl dpchrist.pl sudoers.0.in
2021-03-02 19:26:04 dpchrist at tinkywinky
~/sandbox/perl/sudoers-secure_path-usr_local_bin
$ diff sudoers.0.in sudoers.0.out.dpchrist
Here is a contrived, but syntactically correct, example that
demonstrates white space, continued lines, and comments. The three
'secure_path' statements do not include the desired path component.
When processed, the component should be added in all three places and
the syntax should be valid:
2021-03-02 19:34:43 dpchrist at tinkywinky
~/sandbox/perl/sudoers-secure_path-usr_local_bin
$ cat sudoers.1.in
# no leading white space
Defaults \
secure_path \
= \
/sbin:/bin:/usr/sbin:/usr/bin \
# trailing comment
# 4 leading spaces
Defaults \
secure_path \
= \
/sbin:/bin:/usr/sbin:/usr/bin \
# trailing comment
# 1 leading tab
Defaults \
secure_path \
= \
/sbin:/bin:/usr/sbin:/usr/bin \
# trailing comment
2021-03-02 19:34:49 dpchrist at tinkywinky
~/sandbox/perl/sudoers-secure_path-usr_local_bin
$ /usr/sbin/visudo -c -s -f sudoers.1.in
sudoers.1.in: parsed OK
2021-03-02 19:35:00 dpchrist at tinkywinky
~/sandbox/perl/sudoers-secure_path-usr_local_bin
$ perl dpchrist.pl sudoers.1.in
2021-03-02 19:35:08 dpchrist at tinkywinky
~/sandbox/perl/sudoers-secure_path-usr_local_bin
$ cat sudoers.1.out.dpchrist
# no leading white space
Defaults \
secure_path \
= \
/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin \
# trailing comment
# 4 leading spaces
Defaults \
secure_path \
= \
/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin \
# trailing comment
# 1 leading tab
Defaults \
secure_path \
= \
/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin \
# trailing comment
2021-03-02 19:35:22 dpchrist at tinkywinky
~/sandbox/perl/sudoers-secure_path-usr_local_bin
$ /usr/sbin/visudo -c -s -f sudoers.1.out.dpchrist
sudoers.1.out.dpchrist: parsed OK
David
More information about the SanFrancisco-pm
mailing list