I looked around for this and got frustrated with how hard it was. Then I finally found the correct recipie, and I post it here. Use this code when you write a perl server that needs to do some root stuff and then give up root privilages. The group name and user name are probably in your config setup somehow.
sub switchUsers { my ($uname,$gname)=@_;
eval('getgrnam(root);getpwnam(root);');
if($@) {
# windows pukes "unimplemented" for these -- just skip it
mlog("Warning: uname and/or gname are set ($uname,$gname) but getgrn
+am / getpwnam give errors");
return;
}
$>=0;
if($> != 0) {
mlog("requested to switch to user/group '$uname/$gname' but cannot s
+et effective uid to 0 -- quitting; uid is $>");
die "requested to switch to user/group '$uname/$gname' but cannot se
+t effective uid to 0 -- quitting; uid is $>\n";
}
$<=0;
if($gname) {
my $gid = getgrnam($gname);
if(defined $gid) {
$)="$gid $gid";
if($)+0==$gid) {
mlog("Switched effective gid to $gid ($gname)");
} else {
mlog("Failed to switch effective gid to $gid ($gname) -- effective
+ gid=$) -- quitting");
die "Failed to switch effective gid to $gid ($gname) -- effective
+gid=$) -- quitting";
}
$(="$gid $gid";
if($(+0==$gid) {
mlog("Switched real gid to $gid ($gname)");
} else {
mlog("Failed to switch real gid to $gid ($gname) -- real uid=$(");
}
} else {
mlog("Could not find gid for group '$gname' -- not switching effect
+ive gid -- quitting");
die "Could not find gid for group '$gname' -- not switching effecti
+ve gid -- quitting";
}
}
if($uname) {
my $uid = getpwnam($uname);
if(defined $uid) {
# do it both ways so linux and bsd are happy
$<=$uid; $>=$uid; $<=$uid; $>=$uid;
if($>==$uid) {
mlog("Switched effective uid to $uid ($uname)");
} else {
mlog("Failed to switch effective uid to $uid ($uname) -- real uid=
+$< -- quitting");
die "Failed to switch effective uid to $uid ($uname) -- real uid=$
+< -- quitting";
}
if($<==$uid) {
mlog("Switched real uid to $uid ($uname)");
} else {
mlog("Failed to switch real uid to $uid ($uname) -- real uid=$<");
}
} else {
mlog("Could not find uid for user '$uname' -- not switching effecti
+ve uid -- quitting");
die "Could not find uid for user '$uname' -- not switching effectiv
+e uid -- quitting";
}
}
}
sub mlog {print @_,"\n";}