File Coverage

blib/lib/Protocol/DBus/Authn/Mechanism/EXTERNAL.pm
Criterion Covered Total %
statement 21 37 56.7
branch 2 6 33.3
condition 2 9 22.2
subroutine 6 7 85.7
pod 0 3 0.0
total 31 62 50.0


line stmt bran cond sub pod time code
1             package Protocol::DBus::Authn::Mechanism::EXTERNAL;
2              
3 4     4   1636 use strict;
  4         8  
  4         92  
4 4     4   20 use warnings;
  4         8  
  4         116  
5              
6 4     4   24 use parent 'Protocol::DBus::Authn::Mechanism';
  4         4  
  4         20  
7              
8 4     4   128 use Protocol::DBus::Socket ();
  4         8  
  4         1212  
9              
10             # The methods of user credential retrieval that the reference D-Bus
11             # server relies on prefer “out-of-band” methods like SO_PEERCRED
12             # on Linux rather than SCM_CREDS. (See See dbus/dbus-sysdeps-unix.c.)
13             # So for some OSes it’s just not necessary to do anything special to
14             # send credentials.
15             #
16             # On other OSes it doesn’t seem possible to send credentials via a
17             # UNIX socket in the first place. But let’s still try.
18             #
19             our @OS_NO_MSGHDR_LIST = (
20              
21             # Reference server doesn’t need our help:
22             'linux',
23             'netbsd', # via LOCAL_PEEREID, which dbus calls
24              
25             # LOCAL_PEERCRED exists and works, but the reference server
26             # doesn’t appear to use it. Nonetheless, EXTERNAL authn works
27             # on these OSes. Maybe getpeereid() calls LOCAL_PEERCRED?
28             'freebsd', # NB: doesn’t work w/ socketpair()
29             'darwin',
30              
31             # 'openbsd', ??? Still trying to test.
32              
33             # No way to pass credentials via UNIX socket,
34             # so let’s just send EXTERNAL and see what happens.
35             # It’ll likely just fail over to DBUS_COOKIE_SHA1.
36             'cygwin',
37             'mswin32',
38             );
39              
40 1     1 0 52 sub INITIAL_RESPONSE { unpack 'H*', $> }
41              
42             # The reference server implementation does a number of things to try to
43             # fetch the peer credentials. .
44             sub must_send_initial {
45 6     6 0 23 my ($self) = @_;
46              
47 6 100       31 if (!defined $self->{'_must_send_initial'}) {
48              
49 5         14 my $can_skip_msghdr = grep { $_ eq $^O } @OS_NO_MSGHDR_LIST;
  30         71  
50              
51 5   33     15 $can_skip_msghdr ||= eval { my $v = Socket::SO_PEERCRED(); 1 };
  0         0  
  0         0  
52 5   33     14 $can_skip_msghdr ||= eval { my $v = Socket::LOCAL_PEEREID(); 1 };
  0         0  
  0         0  
53              
54             # As of this writing it seems FreeBSD and DragonflyBSD do require
55             # Socket::MsgHdr, even though they both have LOCAL_PEERCRED which
56             # should take care of that.
57 5         27 $self->{'_must_send_initial'} = !$can_skip_msghdr;
58             }
59              
60 6         24 return $self->{'_must_send_initial'};
61             }
62              
63             sub send_initial {
64 0     0 0   my ($self, $s) = @_;
65              
66 0 0         eval { require Socket::MsgHdr; 1 } or do {
  0            
  0            
67 0           die "Socket::MsgHdr appears to be needed for EXTERNAL authn (OS=$^O) but failed to load: $@";
68             };
69              
70 0           my $msg = Socket::MsgHdr->new( buf => "\0" );
71              
72             # The kernel should fill in the payload.
73 0           $msg->cmsghdr( Socket::SOL_SOCKET(), Socket::SCM_CREDS(), "\0" x 64 );
74              
75 0           local $!;
76 0           my $ok = Protocol::DBus::Socket::sendmsg_nosignal($s, $msg, 0);
77              
78 0 0 0       if (!$ok && !$!{'EAGAIN'}) {
79 0           die "sendmsg($s): $!";
80             }
81              
82 0           return $ok;
83             }
84              
85             1;