summaryrefslogtreecommitdiffstats
path: root/roles
diff options
context:
space:
mode:
Diffstat (limited to 'roles')
-rwxr-xr-xroles/MSA/files/usr/local/bin/postfix-sender-login.pl20
1 files changed, 13 insertions, 7 deletions
diff --git a/roles/MSA/files/usr/local/bin/postfix-sender-login.pl b/roles/MSA/files/usr/local/bin/postfix-sender-login.pl
index 987482e..5f563c3 100755
--- a/roles/MSA/files/usr/local/bin/postfix-sender-login.pl
+++ b/roles/MSA/files/usr/local/bin/postfix-sender-login.pl
@@ -47,96 +47,102 @@ sub server();
die "This service must be socket-activated.\n"
unless defined $ENV{LISTEN_PID} and $ENV{LISTEN_PID} == $$
and defined $ENV{LISTEN_FDS} and $ENV{LISTEN_FDS} == 1;
open my $S, '+<&=', 3 or die "fdopen: $!";
for (my $i = 0; $i < $nProc-1; $i++) {
my $pid = fork() // die "fork: $!";
unless ($pid) {
server(); # child, never return
exit;
}
}
server();
#############################################################################
sub server() {
while(1) {
accept(my $conn, $S) or do {
- # try again if accept(2) was interrupted by a signal
next if $! == EINTR;
die "accept: $!";
};
my $reply = process_request($conn);
# encode the reply as a netstring and send it back
# https://cr.yp.to/proto/netstrings.txt
$reply = length($reply).':'.$reply.',';
my $len = length($reply);
for (my $i = 0; $i < $len;) {
my $n = syswrite($conn, $reply, $len-$i, $i) // do {
+ next if $! == EINTR;
warn "Can't write: $!";
last;
};
$i += $n;
}
close $conn or warn "Can't close: $!";
}
}
sub process_request($) {
my $conn = shift;
my ($buf, $offset) = (undef, 0);
# keep reading until the request length is determined
do {
- my $n = sysread($conn, $buf, $BUFSIZE, $offset) // return "TEMP can't read: $!";
+ my $n = sysread($conn, $buf, $BUFSIZE, $offset) // do {
+ next if $! == EINTR;
+ return "TEMP can't read: $!";
+ };
return "TEMP EOF" if $n == 0;
$offset += $n;
} until ($buf =~ /\A(0|[1-9][0-9]*):/);
# keep reading until the whole request is buffered
my $strlen = length("$1") + 1; # [len]":"
my $len = $strlen + $1 + 1; # [len]":"[string]","
while ($offset < $len) {
- my $n = sysread($conn, $buf, $BUFSIZE, $offset) // return "TEMP can't read: $!";
+ my $n = sysread($conn, $buf, $BUFSIZE, $offset) // do {
+ next if $! == EINTR;
+ return "TEMP can't read: $!";
+ };
return "TEMP EOF" if $n == 0;
$offset += $n;
}
# requests are of the form $name <space> $key, cf. socketmap_table(5)
my $i = index($buf, ' ', $strlen);
return "TEMP invalid input: $buf" unless $i > $strlen and substr($buf,-1) eq ',';
my $name = substr($buf, $strlen, $i-$strlen);
my $key = substr($buf, $i, -1);
return "TEMP invalid name: $name" unless $name eq 'sender_login';
$key =~ /\A(.+)@([^\@]+)\z/ or return "NOTFOUND "; # invalid sender address
my ($localpart, $domainpart) = ($1, $2);
- my $ldap = Net::LDAPI::->new( $LDAPI )
- // return "TEMP couldn't create Net::LDAPI object";
- $ldap->bind( undef, sasl => Authen::SASL::->new(mechanism => 'EXTERNAL') )
- or return "TEMP LDAP: couldn't bind";
+ my $ldap = Net::LDAPI::->new( $LDAPI ) //
+ return "TEMP couldn't create Net::LDAPI object";
+ $ldap->bind( undef, sasl => Authen::SASL::->new(mechanism => 'EXTERNAL') ) or
+ return "TEMP LDAP: couldn't bind";
my $reply = lookup_sender($ldap, $localpart, $domainpart);
$ldap->unbind();
return $reply;
}
sub lookup_sender($$$) {
my ($ldap, $l, $d) = @_;
my $filter = '(&(objectClass=FripostVirtualDomain)(fvd='.escape_filter_value($d).'))';
my $mesg = $ldap->search( base => $BASEDN, scope => 'one', deref => 'never'
, filter => $filter
, attrs => [qw/objectClass fripostOwner fripostPostmaster/]
);
return "TEMP LDAP error: ".$mesg->error() if $mesg->code;
my $entry = $mesg->pop_entry() // return "NOTFOUND "; # not a domain we know
return "TEMP LDAP error: multiple entry founds" if defined $mesg->pop_entry(); # sanity check
# domain postmasters are allowed to use any sender address
my @logins = $entry->get_value('fripostPostmaster', asref => 0);