| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Ubic::Credentials::OS::MacOSX; | 
| 2 |  |  |  |  |  |  | $Ubic::Credentials::OS::MacOSX::VERSION = '1.59'; | 
| 3 | 1 |  |  | 1 |  | 510 | use strict; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 21 |  | 
| 4 | 1 |  |  | 1 |  | 3 | use warnings; | 
|  | 1 |  |  |  |  | 1 |  | 
|  | 1 |  |  |  |  | 20 |  | 
| 5 |  |  |  |  |  |  |  | 
| 6 | 1 |  |  | 1 |  | 3 | use parent qw(Ubic::Credentials); | 
|  | 1 |  |  |  |  | 1 |  | 
|  | 1 |  |  |  |  | 3 |  | 
| 7 |  |  |  |  |  |  |  | 
| 8 |  |  |  |  |  |  | # ABSTRACT: MacOSX-specific credentials implementation | 
| 9 |  |  |  |  |  |  |  | 
| 10 |  |  |  |  |  |  |  | 
| 11 | 1 |  |  | 1 |  | 39 | use List::MoreUtils qw(uniq); | 
|  | 1 |  |  |  |  | 1 |  | 
|  | 1 |  |  |  |  | 7 |  | 
| 12 |  |  |  |  |  |  |  | 
| 13 | 1 |  |  | 1 |  | 305 | use Params::Validate qw(:all); | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 126 |  | 
| 14 | 1 |  |  | 1 |  | 4 | use Carp; | 
|  | 1 |  |  |  |  | 1 |  | 
|  | 1 |  |  |  |  | 901 |  | 
| 15 |  |  |  |  |  |  |  | 
| 16 |  |  |  |  |  |  | sub new { | 
| 17 | 0 |  |  | 0 | 1 |  | my $class = shift; | 
| 18 | 0 |  |  |  |  |  | my $params = validate(@_, { | 
| 19 |  |  |  |  |  |  | user => 0, | 
| 20 |  |  |  |  |  |  | group => 0, | 
| 21 |  |  |  |  |  |  | service => { optional => 1, isa => 'Ubic::Service' }, | 
| 22 |  |  |  |  |  |  | }); | 
| 23 |  |  |  |  |  |  |  | 
| 24 | 0 |  |  |  |  |  | my $self = {}; | 
| 25 | 0 | 0 |  |  |  |  | if (defined $params->{user}) { | 
|  |  | 0 |  |  |  |  |  | 
| 26 | 0 | 0 |  |  |  |  | if (defined $params->{service}) { | 
| 27 | 0 |  |  |  |  |  | croak "Only one of 'user' and 'service' parameters should be specified"; | 
| 28 |  |  |  |  |  |  | } | 
| 29 | 0 |  |  |  |  |  | $self->{user} = $params->{user}; | 
| 30 | 0 | 0 |  |  |  |  | $self->{group} = $params->{group} if defined $params->{group}; | 
| 31 | 0 | 0 |  |  |  |  | if (ref $self->{group}) { | 
| 32 | 0 |  |  |  |  |  | $self->{group} = $self->{group}[0]; | 
| 33 |  |  |  |  |  |  | } | 
| 34 |  |  |  |  |  |  | } | 
| 35 |  |  |  |  |  |  | elsif (defined $params->{service}) { | 
| 36 | 0 |  |  |  |  |  | $self->{user} = $params->{service}->user; | 
| 37 | 0 |  |  |  |  |  | my @group = $params->{service}->group; | 
| 38 | 0 | 0 |  |  |  |  | $self->{group} = $group[0] if @group; | 
| 39 |  |  |  |  |  |  | } | 
| 40 |  |  |  |  |  |  | else { | 
| 41 | 0 |  |  |  |  |  | $self->{real_user_id} = $<; | 
| 42 | 0 |  |  |  |  |  | $self->{effective_user_id} = $>; | 
| 43 | 0 |  |  |  |  |  | ($self->{real_group_id}) = $( =~ /^(\d+)/; | 
| 44 | 0 |  |  |  |  |  | ($self->{effective_group_id}) = $) =~ /^(\d+)/; | 
| 45 |  |  |  |  |  |  | # TODO - derive user from real_user_id when user is not specified (or from effective_user_id?!) | 
| 46 |  |  |  |  |  |  | } | 
| 47 |  |  |  |  |  |  |  | 
| 48 | 0 |  |  |  |  |  | return bless $self => $class; | 
| 49 |  |  |  |  |  |  | } | 
| 50 |  |  |  |  |  |  |  | 
| 51 |  |  |  |  |  |  | sub user { | 
| 52 | 0 |  |  | 0 | 1 |  | my $self = shift; | 
| 53 | 0 | 0 |  |  |  |  | unless (defined $self->{user}) { | 
| 54 | 0 |  |  |  |  |  | $self->{user} = getpwuid($>); | 
| 55 |  |  |  |  |  |  | } | 
| 56 | 0 |  |  |  |  |  | return $self->{user}; | 
| 57 |  |  |  |  |  |  | } | 
| 58 |  |  |  |  |  |  |  | 
| 59 |  |  |  |  |  |  | sub group { | 
| 60 | 0 |  |  | 0 | 1 |  | my $self = shift; | 
| 61 | 0 | 0 |  |  |  |  | unless (defined $self->{group}) { | 
| 62 | 0 |  |  |  |  |  | $self->_user2group; | 
| 63 |  |  |  |  |  |  | } | 
| 64 | 0 |  |  |  |  |  | return $self->{group}; | 
| 65 |  |  |  |  |  |  | } | 
| 66 |  |  |  |  |  |  |  | 
| 67 |  |  |  |  |  |  | sub _user2uid { | 
| 68 | 0 |  |  | 0 |  |  | my $self = shift; | 
| 69 | 0 |  |  |  |  |  | my $user = $self->user; | 
| 70 | 0 |  |  |  |  |  | my $id = scalar getpwnam($user); | 
| 71 | 0 | 0 |  |  |  |  | unless (defined $id) { | 
| 72 | 0 |  |  |  |  |  | croak "user $user not found"; | 
| 73 |  |  |  |  |  |  | } | 
| 74 | 0 |  |  |  |  |  | return $id; | 
| 75 |  |  |  |  |  |  | } | 
| 76 |  |  |  |  |  |  |  | 
| 77 |  |  |  |  |  |  | sub real_user_id { | 
| 78 | 0 |  |  | 0 | 1 |  | my $self = shift; | 
| 79 | 0 | 0 |  |  |  |  | return $self->{real_user_id} if defined $self->{real_user_id}; | 
| 80 | 0 |  |  |  |  |  | return $self->_user2uid; | 
| 81 |  |  |  |  |  |  | } | 
| 82 |  |  |  |  |  |  |  | 
| 83 |  |  |  |  |  |  | sub effective_user_id { | 
| 84 | 0 |  |  | 0 | 1 |  | my $self = shift; | 
| 85 | 0 | 0 |  |  |  |  | return $self->{effective_user_id} if defined $self->{effective_user_id}; | 
| 86 | 0 |  |  |  |  |  | return $self->_user2uid; | 
| 87 |  |  |  |  |  |  | } | 
| 88 |  |  |  |  |  |  |  | 
| 89 |  |  |  |  |  |  | sub _group2gid { | 
| 90 | 0 |  |  | 0 |  |  | my $self = shift; | 
| 91 | 0 |  |  |  |  |  | my $group = $self->group; | 
| 92 | 0 |  |  |  |  |  | my $gid = getgrnam($group); | 
| 93 | 0 | 0 |  |  |  |  | unless (defined $gid) { | 
| 94 | 0 |  |  |  |  |  | croak "group $group not found"; | 
| 95 |  |  |  |  |  |  | } | 
| 96 | 0 |  |  |  |  |  | return $gid; | 
| 97 |  |  |  |  |  |  | } | 
| 98 |  |  |  |  |  |  |  | 
| 99 |  |  |  |  |  |  | sub real_group_id { | 
| 100 | 0 |  |  | 0 | 1 |  | my $self = shift; | 
| 101 | 0 | 0 |  |  |  |  | return $self->{real_group_id} if defined $self->{real_group_id}; | 
| 102 | 0 |  |  |  |  |  | return $self->_group2gid; | 
| 103 |  |  |  |  |  |  | } | 
| 104 |  |  |  |  |  |  |  | 
| 105 |  |  |  |  |  |  | sub effective_group_id { | 
| 106 | 0 |  |  | 0 | 1 |  | my $self = shift; | 
| 107 | 0 | 0 |  |  |  |  | return $self->{effective_group_id} if defined $self->{effective_group_id}; | 
| 108 | 0 |  |  |  |  |  | return $self->_group2gid; | 
| 109 |  |  |  |  |  |  | } | 
| 110 |  |  |  |  |  |  |  | 
| 111 |  |  |  |  |  |  | sub _user2group { | 
| 112 | 0 |  |  | 0 |  |  | my $self = shift; | 
| 113 | 0 |  |  |  |  |  | my $user = $self->user; | 
| 114 | 0 | 0 |  |  |  |  | confess "user not defined" unless defined $user; | 
| 115 |  |  |  |  |  |  |  | 
| 116 | 0 |  |  |  |  |  | my $main_group = getgrgid((getpwnam $user)[3]); | 
| 117 | 0 |  |  |  |  |  | $self->{group} = $main_group; | 
| 118 |  |  |  |  |  |  | } | 
| 119 |  |  |  |  |  |  |  | 
| 120 |  |  |  |  |  |  | sub set_effective { | 
| 121 | 0 |  |  | 0 | 1 |  | my $self = shift; | 
| 122 |  |  |  |  |  |  |  | 
| 123 | 0 |  |  |  |  |  | my $current_creds = Ubic::Credentials->new; | 
| 124 | 0 |  |  |  |  |  | my $euid = $current_creds->effective_user_id(); | 
| 125 | 0 |  |  |  |  |  | my ($egid) = $current_creds->effective_group_id(); | 
| 126 | 0 |  |  |  |  |  | $egid =~ s/^(\d+).*/$1/; | 
| 127 |  |  |  |  |  |  |  | 
| 128 | 0 |  |  |  |  |  | my $current_user = getpwuid($euid); | 
| 129 | 0 |  |  |  |  |  | my $current_group = getgrgid($egid); | 
| 130 |  |  |  |  |  |  |  | 
| 131 | 0 |  |  |  |  |  | my $user = $self->user; | 
| 132 | 0 |  |  |  |  |  | my ($group) = $self->group; | 
| 133 |  |  |  |  |  |  |  | 
| 134 | 0 | 0 |  |  |  |  | if ($group ne $current_group) { | 
| 135 | 0 |  |  |  |  |  | $self->{old_egid} = $); | 
| 136 | 0 |  |  |  |  |  | my $new_gid = getgrnam($group); | 
| 137 | 0 | 0 |  |  |  |  | unless (defined $new_gid) { | 
| 138 | 0 |  |  |  |  |  | die "group $group not found"; | 
| 139 |  |  |  |  |  |  | } | 
| 140 |  |  |  |  |  |  |  | 
| 141 |  |  |  |  |  |  | # AccessGuard don't need to handle supplementary groups correctly, so this is ok | 
| 142 | 0 |  |  |  |  |  | $) = "$new_gid 0"; | 
| 143 | 0 |  |  |  |  |  | my ($current_gid) = $) =~ /^(\d+)/; | 
| 144 | 0 | 0 |  |  |  |  | if ($current_gid != $new_gid) { | 
| 145 | 0 |  |  |  |  |  | die "Failed to change group from $current_group to $group: $!"; | 
| 146 |  |  |  |  |  |  | } | 
| 147 |  |  |  |  |  |  | } | 
| 148 |  |  |  |  |  |  |  | 
| 149 | 0 | 0 |  |  |  |  | if ($user ne $current_user) { | 
| 150 | 0 |  |  |  |  |  | $self->{old_euid} = $>; | 
| 151 | 0 | 0 |  |  |  |  | if ($current_user ne 'root') { | 
| 152 | 0 |  |  |  |  |  | die "Can't change user from $current_user to $user"; | 
| 153 |  |  |  |  |  |  | } | 
| 154 | 0 |  |  |  |  |  | my $new_uid = getpwnam($user); | 
| 155 | 0 | 0 |  |  |  |  | unless (defined $new_uid) { | 
| 156 | 0 |  |  |  |  |  | die "user $user not found"; | 
| 157 |  |  |  |  |  |  | } | 
| 158 | 0 |  |  |  |  |  | $> = $new_uid; | 
| 159 | 0 | 0 |  |  |  |  | if ($> != $new_uid) { | 
| 160 | 0 |  |  |  |  |  | die "Failed to change user from $current_user to $user: $!"; | 
| 161 |  |  |  |  |  |  | } | 
| 162 |  |  |  |  |  |  | } | 
| 163 |  |  |  |  |  |  | } | 
| 164 |  |  |  |  |  |  |  | 
| 165 |  |  |  |  |  |  | sub _groups_equal { | 
| 166 | 0 |  |  | 0 |  |  | my ($self, $g1, $g2) = @_; | 
| 167 | 0 |  |  |  |  |  | my ($main1) = split / /, $g1; | 
| 168 | 0 |  |  |  |  |  | my ($main2) = split / /, $g2; | 
| 169 | 0 |  |  |  |  |  | return ($main1 == $main2); | 
| 170 |  |  |  |  |  |  | } | 
| 171 |  |  |  |  |  |  |  | 
| 172 |  |  |  |  |  |  |  | 
| 173 |  |  |  |  |  |  | sub reset_effective { | 
| 174 | 0 |  |  | 0 | 1 |  | my $self = shift; | 
| 175 |  |  |  |  |  |  |  | 
| 176 | 0 | 0 |  |  |  |  | if (defined $self->{old_euid}) { | 
| 177 | 0 |  |  |  |  |  | $> = $self->{old_euid}; # return euid back to normal | 
| 178 | 0 | 0 |  |  |  |  | if ($> != $self->{old_euid}) { | 
| 179 | 0 |  |  |  |  |  | warn "Failed to restore euid from $> to $self->{old_euid}: $!"; | 
| 180 |  |  |  |  |  |  | } | 
| 181 |  |  |  |  |  |  | } | 
| 182 | 0 | 0 |  |  |  |  | if (defined $self->{old_egid}) { | 
| 183 | 0 |  |  |  |  |  | $) = $self->{old_egid}; # return egid back to normal | 
| 184 | 0 | 0 |  |  |  |  | if ($) != $self->{old_egid}) { | 
| 185 | 0 |  |  |  |  |  | warn "Failed to restore egid from '$)' to '$self->{old_egid}': $!"; | 
| 186 |  |  |  |  |  |  | } | 
| 187 |  |  |  |  |  |  | } | 
| 188 |  |  |  |  |  |  | } | 
| 189 |  |  |  |  |  |  |  | 
| 190 |  |  |  |  |  |  | sub eq { | 
| 191 | 0 |  |  | 0 | 1 |  | my ($self, $other) = @_; | 
| 192 | 0 | 0 | 0 |  |  |  | if ( | 
|  |  |  | 0 |  |  |  |  | 
|  |  |  | 0 |  |  |  |  | 
| 193 |  |  |  |  |  |  | $self->effective_user_id == $other->effective_user_id | 
| 194 |  |  |  |  |  |  | and $self->real_user_id == $other->real_user_id | 
| 195 |  |  |  |  |  |  | and $self->_groups_equal($self->effective_group_id, $other->effective_group_id) | 
| 196 |  |  |  |  |  |  | and $self->_groups_equal($self->real_group_id, $other->real_group_id) | 
| 197 |  |  |  |  |  |  | ) { | 
| 198 | 0 |  |  |  |  |  | return 1; | 
| 199 |  |  |  |  |  |  | } | 
| 200 |  |  |  |  |  |  | else { | 
| 201 | 0 |  |  |  |  |  | return; | 
| 202 |  |  |  |  |  |  | } | 
| 203 |  |  |  |  |  |  | } | 
| 204 |  |  |  |  |  |  |  | 
| 205 |  |  |  |  |  |  | sub set { | 
| 206 | 0 |  |  | 0 | 1 |  | my ($self) = @_; | 
| 207 | 0 |  |  |  |  |  | my $effective_gid = $self->effective_group_id; | 
| 208 | 0 |  |  |  |  |  | $) = $effective_gid; | 
| 209 | 0 | 0 |  |  |  |  | unless ($self->_groups_equal($), $effective_gid)) { | 
| 210 | 0 |  |  |  |  |  | die "Failed to set effective gid to $effective_gid: $!"; | 
| 211 |  |  |  |  |  |  | } | 
| 212 | 0 |  |  |  |  |  | my $new_euid = $self->effective_user_id; | 
| 213 | 0 |  |  |  |  |  | $> = $new_euid; | 
| 214 | 0 | 0 |  |  |  |  | unless ($> == $new_euid) { | 
| 215 | 0 |  |  |  |  |  | die "Failed to set effective uid to $new_euid: $!"; | 
| 216 |  |  |  |  |  |  | } | 
| 217 | 0 |  |  |  |  |  | my $real_gid = $self->real_group_id; | 
| 218 | 0 |  |  |  |  |  | $( = $real_gid; | 
| 219 | 0 | 0 |  |  |  |  | unless ($self->_groups_equal($(, $real_gid)) { | 
| 220 | 0 |  |  |  |  |  | die "Failed to set real gid to $real_gid: $!"; | 
| 221 |  |  |  |  |  |  | } | 
| 222 | 0 |  |  |  |  |  | my $new_ruid = $self->real_user_id; | 
| 223 | 0 |  |  |  |  |  | $< = $new_ruid; | 
| 224 | 0 | 0 |  |  |  |  | unless ($< == $new_ruid) { | 
| 225 | 0 |  |  |  |  |  | die "Failed to set real uid to $new_ruid: $!"; | 
| 226 |  |  |  |  |  |  | } | 
| 227 |  |  |  |  |  |  | } | 
| 228 |  |  |  |  |  |  |  | 
| 229 |  |  |  |  |  |  |  | 
| 230 |  |  |  |  |  |  | 1; | 
| 231 |  |  |  |  |  |  |  | 
| 232 |  |  |  |  |  |  | __END__ |