use reusable I/O utils, more solid error handling
[scpubgit/System-Introspector.git] / lib / System / Introspector / Sudoers.pm
1 package System::Introspector::Sudoers;
2 use Moo;
3
4 use System::Introspector::Util qw(
5     handle_from_command
6     files_from_dir
7     output_from_file
8     transform_exceptions
9 );
10
11 has sudoers_file => (
12     is      => 'ro',
13     default => sub { '/etc/sudoers' },
14 );
15
16 has hostname => (
17     is      => 'ro',
18     default => sub { scalar `hostname` },
19 );
20
21 sub gather {
22     my ($self) = @_;
23     my %file = $self->_gather_files($self->sudoers_file);
24     return \%file;
25 }
26
27 sub _gather_files {
28     my ($self, $file) = @_;
29     my $result = transform_exceptions {
30         my @lines = output_from_file $file;
31         my @result = ({ body => join '', @lines });
32         for my $line (@lines) {
33             chomp $line;
34             if ($line =~ m{^#include\s+(.+)$}) {
35                 my $inc_file = $self->_insert_hostname($1);
36                 push @result, $self->_gather_files($inc_file);
37             }
38             elsif ($line =~ m{^#includedir\s+(.+)$}) {
39                 my $inc_dir = $self->_insert_hostname($1);
40                 push @result, $self->_gather_from_dir($inc_dir);
41             }
42         }
43         return \@result;
44     };
45     return $file => @$result;
46 }
47
48 sub _gather_from_dir {
49     my ($self, $dir) = @_;
50     my @files = files_from_dir $dir;
51     my %file;
52     for my $file (@files) {
53         next if $file =~ m{\.} or $file =~ m{~$};
54         %file = (%file, $self->_gather_files("$dir/$file"));
55     }
56     return %file;
57 }
58
59 sub _insert_hostname {
60     my ($self, $value) = @_;
61     my $hostname = $self->hostname;
62     $value =~ s{\%h}{$hostname}g;
63     return $value;
64 }
65
66 1;
67
68 __END__
69
70 =head1 NAME
71
72 System::Introspector::Sudoers - Gather sudoer information
73
74 =head1 DESCRIPTION
75
76 Reads C<sudoers> files to gather information about sudo abilities. This
77 probe will also read all included files.
78
79 =head1 ATTRIBUTES
80
81 =head2 sudoers_file
82
83 The path to the original C<sudoers> file that should be read. Includes from this
84 file will be followed and provided as well.
85
86 =head2 hostname
87
88 The hostname used to resolve C<%h> hostname markers in inclusions.
89
90 =head1 SEE ALSO
91
92 =over
93
94 =item L<System::Introspector>
95
96 =back
97
98 =cut
99