line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Privileges::Drop; |
2
|
1
|
|
|
1
|
|
21495
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
34
|
|
3
|
1
|
|
|
1
|
|
4
|
use warnings; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
27
|
|
4
|
1
|
|
|
1
|
|
763
|
use English qw( -no_match_vars ); |
|
1
|
|
|
|
|
4653
|
|
|
1
|
|
|
|
|
6
|
|
5
|
1
|
|
|
1
|
|
408
|
use Carp; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
84
|
|
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
our $VERSION = '1.03'; |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
=head1 NAME |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
Privileges::Drop - A module to make it simple to drop all privileges, even |
12
|
|
|
|
|
|
|
POSIX groups. |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
=head1 DESCRIPTION |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
This module tries to simplify the process of dropping privileges. This can be |
17
|
|
|
|
|
|
|
useful when your Perl program needs to bind to privileged ports, etc. This |
18
|
|
|
|
|
|
|
module is much like Proc::UID, except that it's implemented in pure Perl. |
19
|
|
|
|
|
|
|
Special care has been taken to also drop saved uid on platforms that support |
20
|
|
|
|
|
|
|
this, currently only test on on Linux. |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
=head1 SYNOPSIS |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
use Privileges::Drop; |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
# Do privileged stuff |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
# Drops privileges and sets euid/uid to 1000 and egid/gid to 1000. |
29
|
|
|
|
|
|
|
drop_uidgid(1000, 1000); |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
# Drop privileges to user nobody looking up gid and uid with getpwname |
32
|
|
|
|
|
|
|
# This also set the enviroment variables USER, LOGNAME, HOME and SHELL. |
33
|
|
|
|
|
|
|
drop_privileges('nobody'); |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
=head1 METHODS |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
=over |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
=cut |
40
|
|
|
|
|
|
|
|
41
|
1
|
|
|
1
|
|
4
|
use base "Exporter"; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
699
|
|
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
our @EXPORT = qw(drop_privileges drop_uidgid); |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
=item drop_uidgid($uid, $gid, @groups) |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
Drops privileges and sets euid/uid to $uid and egid/gid to $gid. |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
Supplementary groups can be set in @groups. |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
=cut |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
sub drop_uidgid { |
54
|
0
|
|
|
0
|
1
|
|
my ($uid, $gid, @reqPosixGroups) = @_; |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
# Sort the groups and make sure they are uniq |
57
|
0
|
|
|
|
|
|
my %groupHash = map { $_ => 1 } ($gid, @reqPosixGroups); |
|
0
|
|
|
|
|
|
|
58
|
0
|
|
|
|
|
|
my $newgid ="$gid ".join(" ", sort { $a <=> $b } (keys %groupHash)); |
|
0
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
# Description from: |
61
|
|
|
|
|
|
|
# http://www.mail-archive.com/perl5-changes@perl.org/msg02683.html |
62
|
|
|
|
|
|
|
# |
63
|
|
|
|
|
|
|
# According to Stevens' APUE and various |
64
|
|
|
|
|
|
|
# (BSD, Solaris, HP-UX) man pages setting |
65
|
|
|
|
|
|
|
# the real uid first and effective uid second |
66
|
|
|
|
|
|
|
# is the way to go if one wants to drop privileges, |
67
|
|
|
|
|
|
|
# because if one changes into an effective uid of |
68
|
|
|
|
|
|
|
# non-zero, one cannot change the real uid any more. |
69
|
|
|
|
|
|
|
# |
70
|
|
|
|
|
|
|
# Actually, it gets even messier. There is |
71
|
|
|
|
|
|
|
# a third uid, called the saved uid, and as |
72
|
|
|
|
|
|
|
# long as that is zero, one can get back to |
73
|
|
|
|
|
|
|
# uid of zero. Setting the real-effective *twice* |
74
|
|
|
|
|
|
|
# helps in *most* systems (FreeBSD and Solaris) |
75
|
|
|
|
|
|
|
# but apparently in HP-UX even this doesn't help: |
76
|
|
|
|
|
|
|
# the saved uid stays zero (apparently the only way |
77
|
|
|
|
|
|
|
# in HP-UX to change saved uid is to call setuid() |
78
|
|
|
|
|
|
|
# when the effective uid is zero). |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
# Drop privileges to $uid and $gid for both effective and saved uid/gid |
81
|
0
|
|
|
|
|
|
($GID) = split /\s/, $newgid; |
82
|
0
|
|
|
|
|
|
$EGID = $newgid; |
83
|
0
|
|
|
|
|
|
$EUID = $UID = $uid; |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
# To overwrite the saved UID on all platforms we need to do it twice |
86
|
0
|
|
|
|
|
|
($GID) = split /\s/, $newgid; |
87
|
0
|
|
|
|
|
|
$EGID = $newgid; |
88
|
0
|
|
|
|
|
|
$EUID = $UID = $uid; |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
# Sort the output so we can compare it |
91
|
0
|
|
|
|
|
|
my %GIDHash = map { $_ => 1 } ($gid, split(/\s/, $GID)); |
|
0
|
|
|
|
|
|
|
92
|
0
|
|
|
|
|
|
my $cgid = int($GID)." ".join(" ", sort { $a <=> $b } (keys %GIDHash)); |
|
0
|
|
|
|
|
|
|
93
|
0
|
|
|
|
|
|
my %EGIDHash = map { $_ => 1 } ($gid, split(/\s/, $EGID)); |
|
0
|
|
|
|
|
|
|
94
|
0
|
|
|
|
|
|
my $cegid = int($EGID)." ".join(" ", sort { $a <=> $b } (keys %EGIDHash)); |
|
0
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
# Check that we did actually drop the privileges |
97
|
0
|
0
|
0
|
|
|
|
if($UID ne $uid or $EUID ne $uid or $cgid ne $newgid or $cegid ne $newgid) { |
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
98
|
0
|
|
|
|
|
|
croak("Could not drop privileges to uid:$uid, gid:$newgid\n" |
99
|
|
|
|
|
|
|
."Currently is: UID:$UID, EUID=$EUID, GID=$cgid, EGID=$cegid\n"); |
100
|
|
|
|
|
|
|
} |
101
|
|
|
|
|
|
|
} |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
=item drop_privileges($user) |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
Drops privileges to the $user, looking up gid and uid with getpwname and |
106
|
|
|
|
|
|
|
calling drop_uidgid() with these arguments. |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
The environment variables USER, LOGNAME, HOME and SHELL are also set to the |
109
|
|
|
|
|
|
|
values returned by getpwname. |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
Returns the $uid and $gid on success and dies on error. |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
NOTE: If drop_privileges() is called when you don't have root privileges |
114
|
|
|
|
|
|
|
it will just return undef; |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
=cut |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
sub drop_privileges { |
119
|
0
|
|
|
0
|
1
|
|
my ($user) = @_; |
120
|
|
|
|
|
|
|
|
121
|
0
|
0
|
|
|
|
|
croak "No user give" if !defined $user; |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
# Check if we are root and stop if we are not. |
124
|
0
|
0
|
0
|
|
|
|
if($UID != 0 and $EUID != 0) { |
125
|
0
|
|
|
|
|
|
return; |
126
|
|
|
|
|
|
|
} |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
# Find user in passwd file |
129
|
0
|
|
|
|
|
|
my ($uid, $gid, $home, $shell) = (getpwnam($user))[2,3,7,8]; |
130
|
0
|
0
|
0
|
|
|
|
if(!defined $uid or !defined $gid) { |
131
|
0
|
|
|
|
|
|
croak("Could not find uid and gid user $user"); |
132
|
|
|
|
|
|
|
} |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
# Find all the groups the user is a member of |
135
|
0
|
|
|
|
|
|
my @groups; |
136
|
0
|
|
|
|
|
|
while (my ($name, $comment, $ggid, $mstr) = getgrent()) { |
137
|
0
|
|
|
|
|
|
my %membership = map { $_ => 1 } split(/\s/, $mstr); |
|
0
|
|
|
|
|
|
|
138
|
0
|
0
|
|
|
|
|
if(exists $membership{$user}) { |
139
|
0
|
0
|
|
|
|
|
push(@groups, $ggid) if $ggid ne 0; |
140
|
|
|
|
|
|
|
} |
141
|
|
|
|
|
|
|
} |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
# Cleanup $ENV{} |
144
|
0
|
|
|
|
|
|
$ENV{USER} = $user; |
145
|
0
|
|
|
|
|
|
$ENV{LOGNAME} = $user; |
146
|
0
|
|
|
|
|
|
$ENV{HOME} = $home; |
147
|
0
|
|
|
|
|
|
$ENV{SHELL} = $shell; |
148
|
|
|
|
|
|
|
|
149
|
0
|
|
|
|
|
|
drop_uidgid($uid, $gid, @groups); |
150
|
|
|
|
|
|
|
|
151
|
0
|
|
|
|
|
|
return ($uid, $gid, @groups); |
152
|
|
|
|
|
|
|
} |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
=back |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
=head1 NOTES |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
As this module only uses Perl's build in function, it relies on them to work |
159
|
|
|
|
|
|
|
correctly. That means setting $GID and $EGID should also call setgroups(), |
160
|
|
|
|
|
|
|
something that might not have been the case before Perl 5.004. So if you are |
161
|
|
|
|
|
|
|
running an older version, Proc::UID might be a better choice. |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
=head1 AUTHOR |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
Troels Liebe Bentsen |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
=head1 COPYRIGHT |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
Copyright(C) 2007-2009 Troels Liebe Bentsen |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or modify |
172
|
|
|
|
|
|
|
it under the same terms as Perl itself. |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
=cut |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
1; |