File Coverage

blib/lib/Filesys/POSIX/ReducedPrivileges.pm
Criterion Covered Total %
statement 52 54 96.3
branch 10 12 83.3
condition 2 6 33.3
subroutine 11 11 100.0
pod 2 4 50.0
total 77 87 88.5


line stmt bran cond sub pod time code
1             package Filesys::POSIX::ReducedPrivileges;
2              
3             # Copyright (c) 2016, cPanel, Inc.
4             # All rights reserved.
5             # http://cpanel.net/
6             #
7             # This is free software; you can redistribute it and/or modify it under the same
8             # terms as Perl itself. See the LICENSE file for further details.
9              
10 1     1   368 use Filesys::POSIX::Error qw(throw);
  1         1  
  1         37  
11 1     1   317 use Filesys::POSIX::ReducedPrivileges::Inode ();
  1         2  
  1         15  
12 1     1   299 use Filesys::POSIX::Real;
  1         2  
  1         17  
13 1     1   4 use Carp ();
  1         0  
  1         9  
14 1     1   2 use Errno ();
  1         1  
  1         189  
15              
16             our @ISA = qw(Filesys::POSIX::Real);
17              
18             =head1 NAME
19              
20             Filesys::POSIX::ReducedPrivileges - Portal to actual underlying filesystem as seen by a particular UID/GID.
21              
22             =head1 SYNOPSIS
23              
24             use Filesys::POSIX;
25             use Filesys::POSIX::Real;
26              
27             my $fs = Filesys::POSIX->new(Filesys::POSIX::ReducedPrivileges->new,
28             'path' => '/home/foo/test',
29             'noatime' => 1,
30             'uid' => 99,
31             'gid' => 99,
32             );
33              
34             =head1 DESCRIPTION
35              
36             This module wraps the L filesystem type with entry and
37             exit functions that switch the effective UID and GID whenever the filesystem
38             is accessed.
39              
40             =head1 MOUNT OPTIONS
41              
42             The following values are mandatory:
43              
44             =over
45              
46             =item C
47              
48             The path, in the real filesystem, upon which the new filesystem to be mounted
49             will be based.
50              
51             =item C
52              
53             The numeric UID to use when accessing the real filesystem.
54              
55             =item C
56              
57             The numeric GID to use when accessing the real filesystem. The suppelemental
58             group list is also limited to this GID.
59              
60             =back
61              
62             =cut
63              
64             sub new {
65 3     3 1 1895 my ( $class, %opts ) = @_;
66 3         13 my $self = $class->SUPER::new();
67              
68 3         4 bless $self, $class;
69              
70 3         11 return $self;
71             }
72              
73             sub init {
74 3     3 1 6 my ( $self, %opts ) = @_;
75 3 100       9 my $path = $opts{'path'} or throw &Errno::EINVAL;
76              
77 2         3 $self->{_uid} = $opts{uid};
78 2         5 $self->{_gid} = "$opts{gid} $opts{gid}";
79 2         2 $self->{_privileges_reduced} = 0;
80              
81 2         8 my $root = Filesys::POSIX::ReducedPrivileges::Inode->from_disk( $path, 'dev' => $self );
82              
83 2 100       10 throw &Errno::ENOTDIR unless $root->dir;
84              
85 1         3 $self->{'flags'} = \%opts;
86 1         6 $self->{'path'} = Filesys::POSIX::Path->full($path);
87 1         2 $self->{'root'} = $root;
88              
89 1         2 return $sel;
90             }
91              
92             sub enter_filesystem {
93 14     14 0 11 my $self = shift;
94 14         15 $self->{_privileges_reduced}++;
95 14 100       27 return unless ( $self->{_privileges_reduced} == 1 );
96 9         16 $self->{_original_uid} = $>;
97 9         31 $self->{_original_gid} = $);
98 9         193 $) = $self->{_gid};
99 9         24 $> = $self->{_uid};
100 1     1   3 no warnings 'numeric';
  1         1  
  1         100  
101              
102 9 50 33     63 unless ( $> == $self->{_uid} && int($)) eq int( $self->{_gid} ) ) {
103 0         0 Carp::confess("failed to reduce privileges: $!");
104             }
105 9         17 return;
106             }
107              
108             sub exit_filesystem {
109 14     14 0 15 my $self = shift;
110 14         11 $self->{_privileges_reduced}--;
111 14 100       24 return unless ( $self->{_privileges_reduced} == 0 );
112 9         30 $> = $self->{_original_uid};
113 9         137 $) = $self->{_original_gid};
114 1     1   3 no warnings 'numeric';
  1         1  
  1         66  
115 9 50 33     74 unless ( $> == $self->{_original_uid} && int($)) eq int( $self->{_original_gid} ) ) {
116 0         0 Carp::confess("failed to restore privileges: $!");
117             }
118 9         17 return;
119             }
120              
121             1;
122              
123             __END__