This won't work on Solaris / MacOS / OpenBSD (I think anyway), as they don't support the SO_PEERCRED getsockopt() sub-call.
Solaris is of particular interest to me; I did some digging and found that it supports getting the credentials of the remote peer (to include PF_INET sockets, so long as the remote peer is on the same system e.g. a loopback connection, a process running in another zone, or running at a different level of trust). It does it through a completely different API though; to get started, see the manpages for ucred_get() (describes the whole family) and in particular getpeerucred().
Sun supplies Sun::Solaris::Ucred.pm with the Sun-provided Perl packages, which exposes this API to Perl.
Here's my slapdash implementation for getting peer credentials on both Linux and Solaris (disclaimer: this is a proof of concept, I /know/ there are several glaring problems):
use IO::Socket::UNIX qw( SOCK_STREAM SOMAXCONN SOL_SOCKET
SO_PEERCRED );
# Assume that $socket represents a connected UNIX-domain socket,
# and use it like so:
my ($pid, $uid, $gid) = socket_peercreds($socket);
sub socket_peercreds {
my $socket = shift;
my($gid, $os, $packed, $pid, $ucred, $uid);
chomp($os = `uname -s`);
if($os eq 'Linux'){
$packed = getsockopt($socket, SOL_SOCKET, SO_PEERCRED)
+;
# these are lowercase Ls
($pid, $uid, $gid) = unpack('lll', $packed);
return ($pid, $uid, $gid);
}
elsif($os eq 'SunOS'){
eval "use Sun::Solaris::Ucred qw(getpeerucred ucred_ge
+t ucred_geteuid ucred_getegid ucred_getpid);
";
$ucred = getpeerucred(fileno($socket));
if(! defined($ucred)){
print "ERROR: getpeerucred() failed: $!\n";
print "\$ucred: $ucred\n";
return undef;
}
$uid = ucred_geteuid($ucred);
$gid = ucred_getegid($ucred);
$pid = ucred_getpid($ucred);
return ($pid, $uid, $gid);
}
else {
print "ERROR: Unknown os, can't get peer's creds\n";
return undef;
}
}
| [reply] [d/l] |