~ubuntu-branches/ubuntu/utopic/spamassassin/utopic-updates

« back to all changes in this revision

Viewing changes to .pc/10_change_config_paths/spamd/spamd.raw

  • Committer: Package Import Robot
  • Author(s): Noah Meyerhans
  • Date: 2014-02-14 22:45:15 UTC
  • mfrom: (0.8.1) (0.6.2) (5.1.22 sid)
  • Revision ID: package-import@ubuntu.com-20140214224515-z1es2twos8xh7n2y
Tags: 3.4.0-1
* New upstream version! (Closes: 738963, 738872, 738867)
* Scrub the environment when switching to the debian-spamd user in
  postinst and cron.daily. (Closes: 738951)
* Enhancements to postinst to better manage ownership of
  /var/lib/spamassassin, via Iain Lane <iain.lane@canonical.com>
  (Closes: 738974)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#!/usr/bin/perl -w -T
 
1
#!/usr/bin/perl -T -w
2
2
# <@LICENSE>
3
3
# Licensed to the Apache Software Foundation (ASF) under one or more
4
4
# contributor license agreements.  See the NOTICE file distributed with
16
16
# limitations under the License.
17
17
# </@LICENSE>
18
18
 
 
19
#IMPORTANT: The order of -T -w above is important for spamd_hup.t on Solaris 10 - changed per bug 6883
 
20
 
 
21
use strict;
 
22
use warnings;
 
23
use re 'taint';
 
24
 
19
25
my $PREFIX          = '@@PREFIX@@';             # substituted at 'make' time
20
26
my $DEF_RULES_DIR   = '@@DEF_RULES_DIR@@';      # substituted at 'make' time
21
27
my $LOCAL_RULES_DIR = '@@LOCAL_RULES_DIR@@';    # substituted at 'make' time
32
38
  }                                                 # REMOVEFORINST
33
39
}
34
40
 
35
 
use strict;
36
 
use warnings;
37
 
use re 'taint';
38
 
 
39
 
# Big Ugly Hack; purpose: don't force requirement on IO::Socket::INET6
 
41
use vars qw($have_getaddrinfo_in_core $have_getaddrinfo_legacy
 
42
            $io_socket_module_name $have_inet4 $have_inet6
 
43
            $ai_addrconfig_flag);
 
44
# don't force requirement on IO::Socket::IP or IO::Socket::INET6
40
45
BEGIN {
41
 
  use Socket;
42
 
  eval {
43
 
    require IO::Socket::INET6;
 
46
  use Socket qw(:DEFAULT IPPROTO_TCP);
 
47
 
 
48
  # AUTOLOADing 'constants' here enables inlining - see Exporter man page
 
49
  &SOCK_STREAM; &IPPROTO_TCP; &SOMAXCONN;
 
50
 
 
51
  $have_getaddrinfo_in_core = eval {
 
52
    # The Socket module (1.94) bundled with Perl 5.14.* provides
 
53
    # new affordances for IPv6, including implementations of the
 
54
    # Socket::getaddrinfo() and Socket::getnameinfo() functions,
 
55
    # along with related constants and a handful of new functions.
 
56
    # Perl 5.16.0 upgrades the core Socket module to version 2.001.
 
57
  # Socket->VERSION(1.94);  # provides getaddrinfo() and getnameinfo()
 
58
  # Socket->VERSION(1.95);  # provides AI_ADDRCONFIG
 
59
    Socket->VERSION(1.96);  # provides NIx_NOSERV, and Exporter tag :addrinfo
 
60
  # Socket->VERSION(1.97);  # IO::Socket::IP depends on Socket 1.97
 
61
    import Socket qw(/^(?:AI|NI|NIx|EAI)_/);
 
62
    &AI_ADDRCONFIG; &AI_PASSIVE;  # enable inlining
 
63
    &NI_NUMERICHOST, &NI_NUMERICSERV; &NIx_NOSERV; 1;
 
64
  };
 
65
 
 
66
  $have_getaddrinfo_legacy = !$have_getaddrinfo_in_core && eval {
44
67
    require Socket6;
 
68
  # Socket6->VERSION(0.13);  # provides NI_NAMEREQD
 
69
    Socket6->VERSION(0.18);  # provides AI_NUMERICSERV
 
70
    import Socket6 qw(/^(?:AI|NI|NIx|EAI)_/);
 
71
    &AI_ADDRCONFIG; &AI_PASSIVE;  # enable inlining
 
72
    &NI_NUMERICHOST; &NI_NUMERICSERV; &NI_NAMEREQD; 1;
45
73
  };
46
 
  if ($@) {    # IPv4 only
47
 
    require IO::Socket::INET;
48
 
    *new_io_socket_inetx = sub { IO::Socket::INET->new(@_); };
49
 
    *ip_or_name_to_ip    = sub {
50
 
      my $in_addr = (gethostbyname(shift))[4] or return undef;
51
 
      Socket::inet_ntoa($in_addr);
52
 
    };
53
 
    *peer_info_from_socket = sub {
54
 
      my $sock = shift;
55
 
      my ($port, $in_addr) = Socket::sockaddr_in($sock->peername)
 
74
 
 
75
  &AF_UNSPEC; &AF_INET; &AF_INET6;  # enable inlining
 
76
 
 
77
  $ai_addrconfig_flag = 0;
 
78
 
 
79
  if ($have_getaddrinfo_in_core) {
 
80
    # using a modern Socket module
 
81
 
 
82
    eval {  # does the operating system recognize an AI_ADDRCONFIG flag?
 
83
      if (&AI_ADDRCONFIG && &EAI_BADFLAGS) {
 
84
        my($err, @res) = Socket::getaddrinfo("localhost", 0,
 
85
                           { family => &AF_UNSPEC, flags => &AI_ADDRCONFIG });
 
86
        $ai_addrconfig_flag = &AI_ADDRCONFIG if !$err || $err != &EAI_BADFLAGS;
 
87
      }
 
88
    };
 
89
 
 
90
    *ip_or_name_to_ip_addresses = sub {
 
91
      my($addr, $ai_family) = @_;
 
92
      # Socket::getaddrinfo returns a list of hashrefs
 
93
      my($error, @res) =
 
94
        Socket::getaddrinfo($addr, 0,
 
95
          { family => $ai_family, flags => $ai_addrconfig_flag | &AI_PASSIVE, 
 
96
            socktype => &SOCK_STREAM, protocol => &IPPROTO_TCP });
 
97
      my(@ip_addrs);
 
98
      if (!$error) {
 
99
        for my $a (@res) {
 
100
          my($err, $ip_addr) =
 
101
            Socket::getnameinfo($a->{addr},
 
102
                                &NI_NUMERICHOST | &NI_NUMERICSERV, &NIx_NOSERV);
 
103
          if (!$err) { push(@ip_addrs, $ip_addr) }
 
104
          elsif (!$error) { $error = $err }
 
105
        }
 
106
      }
 
107
      return ($error, @ip_addrs);
 
108
    };
 
109
 
 
110
    *peer_info_from_socket = sub {
 
111
      my $sock = shift;
 
112
      my $peer_addr = $sock->peerhost;  # textual representation of an IP addr
 
113
      $peer_addr or return;
 
114
      my $peer_hostname;
 
115
      if ($sock->UNIVERSAL::can('peerhostname')) {
 
116
        $peer_hostname = $sock->peerhostname;  # provided by IO::Socket::IP
 
117
      } else {
 
118
        my($err, $host) = Socket::getnameinfo($sock->peername,
 
119
                                              &NI_NAMEREQD, &NIx_NOSERV);
 
120
        $peer_hostname = $host  if !$err;
 
121
      }
 
122
      return ($sock->peerport, $peer_addr, $peer_hostname||$peer_addr,
 
123
              $sock->sockport);
 
124
    };
 
125
 
 
126
  } elsif ($have_getaddrinfo_legacy) {
 
127
    # using a legacy Socket6 module; somewhat different API on getaddrinfo()
 
128
    # and getnameinfo() compared to these functions in a module Socket
 
129
 
 
130
    eval {  # does the operating system recognize an AI_ADDRCONFIG flag?
 
131
      if (&AI_ADDRCONFIG && &EAI_BADFLAGS) {
 
132
        my @res = Socket6::getaddrinfo("localhost", "", 0, &SOCK_STREAM,
 
133
                                       &IPPROTO_TCP, &AI_ADDRCONFIG);
 
134
        my $err = @res >= 5 ? 0 : $res[0];
 
135
        $ai_addrconfig_flag = &AI_ADDRCONFIG if !$err || $err != &EAI_BADFLAGS;
 
136
      }
 
137
    };
 
138
 
 
139
    *ip_or_name_to_ip_addresses = sub {
 
140
      my($addr, $ai_family) = @_;
 
141
      # Socket6::getaddrinfo returns a list of quintuples
 
142
      my @res = Socket6::getaddrinfo($addr, '',
 
143
                                     $ai_family, &SOCK_STREAM, &IPPROTO_TCP,
 
144
                                     $ai_addrconfig_flag | &AI_PASSIVE);
 
145
      my($error, @ip_addrs);
 
146
      if (@res < 5) {
 
147
        $error = $res[0];
 
148
      } else {
 
149
        my($family, $socktype, $proto, $saddr, $canonname);
 
150
        while (@res >= 5) {
 
151
          ($family, $socktype, $proto, $saddr, $canonname, @res) = @res;
 
152
          my(@resinfo) =
 
153
            Socket6::getnameinfo($saddr, &NI_NUMERICHOST | &NI_NUMERICSERV);
 
154
          if (@resinfo >= 2) { push(@ip_addrs, $resinfo[0]) }
 
155
          elsif (!$error) { $error = $resinfo[0] }
 
156
        }
 
157
      }
 
158
      return ($error, @ip_addrs);
 
159
    };
 
160
 
 
161
    *peer_info_from_socket = sub {
 
162
      my $sock = shift;
 
163
      my $peer_addr = $sock->peerhost;
 
164
      $peer_addr or return;
 
165
      my @resinfo = (Socket6::getnameinfo($sock->peername, &NI_NAMEREQD))[0];
 
166
      my $peer_hostname = @resinfo > 1 ? $resinfo[0] : undef;
 
167
      return ($sock->peerport, $peer_addr, $peer_hostname||$peer_addr,
 
168
              $sock->sockport);
 
169
    };
 
170
 
 
171
  } else {  # IPv4 only, no getaddrinfo() available
 
172
 
 
173
    *ip_or_name_to_ip_addresses = sub {
 
174
      my($addr, $ai_family) = @_;
 
175
      $ai_family == &AF_UNSPEC || $ai_family == &AF_INET
 
176
        or die "Protocol family $ai_family not supported on this platform";
 
177
      my($error, @ip_addrs, @binaddr);
 
178
      $! = 0; my @res = gethostbyname($addr);
 
179
      if (!@res) {
 
180
        $error = "no results from gethostbyname $!";
 
181
      } else {
 
182
        my($name,$aliases,$addrtype,$length);
 
183
        ($name,$aliases,$addrtype,$length,@binaddr) = @res;
 
184
      }
 
185
      if (!@binaddr) {
 
186
        $error = "no such host";
 
187
      } else {
 
188
        for (@binaddr) {
 
189
          my $ip_addr = Socket::inet_ntoa($_);
 
190
          push(@ip_addrs, $ip_addr)  if $ip_addr;
 
191
        }
 
192
      }
 
193
      return ($error, @ip_addrs);
 
194
    };
 
195
 
 
196
    *peer_info_from_socket = sub {
 
197
      my $sock = shift;
 
198
      my ($peer_port, $in_addr) = Socket::sockaddr_in($sock->peername)
56
199
        or return;
57
 
      my $addr = Socket::inet_ntoa($in_addr) or return;
58
 
      my $host = gethostbyaddr($in_addr, Socket::AF_INET()) || $addr;
59
 
      return ($port, $addr, $host);
60
 
    };
61
 
  }
62
 
  else {    # IPv4+IPv6
63
 
    *new_io_socket_inetx = sub { IO::Socket::INET6->new(@_); };
64
 
    *ip_or_name_to_ip    = sub {
65
 
      my $addr = (
66
 
        Socket6::getaddrinfo(
67
 
          shift, '', Socket::AF_UNSPEC(), Socket::SOCK_STREAM()
68
 
        )
69
 
        )[3]
70
 
        or return undef;
71
 
      $addr = (Socket6::getnameinfo($addr, Socket6::NI_NUMERICHOST()))[0];
72
 
    };
73
 
    *peer_info_from_socket = sub {
74
 
      my $sock = shift;
75
 
      my $addr = $sock->peerhost or return;
76
 
      my $host =
77
 
        (Socket6::getnameinfo($sock->peername, Socket6::NI_NAMEREQD()))[0]
78
 
        || $addr;
79
 
      return ($sock->peerport(), $addr, $host);
80
 
    };
81
 
  }
 
200
      my $peer_addr = Socket::inet_ntoa($in_addr) or return;
 
201
      my $peer_hostname = gethostbyaddr($in_addr, &AF_INET);
 
202
      return ($peer_port, $peer_addr, $peer_hostname||$peer_addr,
 
203
              $sock->sockport);
 
204
    };
 
205
 
 
206
  }
 
207
 
 
208
  if (eval { require IO::Socket::IP }) {  # handles IPv6 and IPv4
 
209
    IO::Socket::IP->VERSION(0.09);  # implements IPV6_V6ONLY
 
210
    $io_socket_module_name = 'IO::Socket::IP';
 
211
 
 
212
  } elsif (eval { require IO::Socket::INET6 }) {  # handles IPv6 and IPv4
 
213
    $io_socket_module_name = 'IO::Socket::INET6';
 
214
 
 
215
  } elsif (eval { require IO::Socket::INET }) {  # IPv4 only
 
216
    $io_socket_module_name = 'IO::Socket::INET';
 
217
  }
 
218
 
 
219
  $have_inet4 =  # can we create a PF_INET socket?
 
220
    defined $io_socket_module_name && eval {  
 
221
      my $sock =
 
222
        $io_socket_module_name->new(LocalAddr => '0.0.0.0', Proto => 'tcp');
 
223
      $sock->close or die "error closing socket: $!"  if $sock;
 
224
      $sock ? 1 : undef;
 
225
    };
 
226
 
 
227
  $have_inet6 =  # can we create a PF_INET6 socket?
 
228
    defined $io_socket_module_name &&
 
229
    $io_socket_module_name ne 'IO::Socket::INET' &&
 
230
    eval {
 
231
      my $sock =
 
232
        $io_socket_module_name->new(LocalAddr => '::', Proto => 'tcp');
 
233
      $sock->close or die "error closing socket: $!"  if $sock;
 
234
      $sock ? 1 : undef;
 
235
    };
 
236
 
82
237
}
83
238
 
84
239
use IO::Handle;
85
240
use IO::Pipe;
 
241
use IO::File ();
86
242
 
87
243
use Mail::SpamAssassin;
88
244
use Mail::SpamAssassin::NetSet;
89
245
use Mail::SpamAssassin::SubProcBackChannel;
90
246
use Mail::SpamAssassin::SpamdForkScaling qw(:pfstates);
91
247
use Mail::SpamAssassin::Logger qw(:DEFAULT log_message);
92
 
use Mail::SpamAssassin::Util qw(untaint_var exit_status_str
93
 
                                am_running_on_windows);
 
248
use Mail::SpamAssassin::Util qw(untaint_var untaint_file_path
 
249
                                exit_status_str am_running_on_windows);
94
250
use Mail::SpamAssassin::Timeout;
95
251
 
96
252
use Getopt::Long;
97
253
use POSIX qw(:sys_wait_h);
98
 
use POSIX qw(setsid sigprocmask _exit);
 
254
use POSIX qw(locale_h setsid sigprocmask _exit);
99
255
use Errno;
 
256
use Fcntl qw(:flock);
100
257
 
101
258
use Cwd ();
102
259
use File::Spec 0.8;
112
269
  die 'spamd: spamd script is v@@VERSION@@, but using modules v'.$Mail::SpamAssassin::VERSION."\n";
113
270
}
114
271
 
115
 
BEGIN {
116
 
  # redirect __WARN__ and __DIE__
117
 
  # do not trap warnings here based on eval scope; evals are very
118
 
  # common throughout.  die()s can be trapped though.
119
 
  $SIG{__WARN__} = sub {
120
 
    log_message("warn", $_[0]);
121
 
  };
122
 
  $SIG{__DIE__} = sub {
123
 
    # see http://use.perl.org/comments.pl?mode=flat&sid=33872 for $^S
124
 
    log_message("error", $_[0]) unless $^S;
125
 
  };
126
 
}
 
272
# Bug 3062: SpamAssassin should be "locale safe"
 
273
POSIX::setlocale(LC_TIME,'C');
127
274
 
128
275
my %resphash = (
129
276
  EX_OK          => 0,     # no problems
226
373
  'helper-home-dir|H:s'      => \$opt{'home_dir_for_helpers'},
227
374
  'help|h'                   => \$opt{'help'},
228
375
  'ident-timeout=f'          => \$opt{'ident-timeout'},
229
 
  'ipv4only|ipv4-only|ipv4'  => \$opt{'force_ipv4'},
 
376
  '4|ipv4only|ipv4-only|ipv4'=> sub { $opt{'force_ipv4'} = 1;
 
377
                                      $opt{'force_ipv6'} = 0; },
 
378
  '6'                        => sub { $opt{'force_ipv6'} = 1;
 
379
                                      $opt{'force_ipv4'} = 0; },
230
380
  'ldap-config!'             => \$opt{'ldap-config'},
231
 
  'listen-ip|ip-address|i:s' => \$opt{'listen-ip'},
 
381
  'listen|listen-ip|ip-address|i:s' => \@{ $opt{'listen-sockets'} },
232
382
  'local!'                   => \$opt{'local'},
233
383
  'L'                        => \$opt{'local'},
234
384
  'l'                        => \$opt{'tell'},
332
482
  )
333
483
  )
334
484
{
335
 
  $opt{$opt} = Mail::SpamAssassin::Util::untaint_file_path(
336
 
    File::Spec->rel2abs( $opt{$opt} )    # rel2abs taints the new value!
337
 
  ) if ( $opt{$opt} );
338
 
}
339
 
 
340
 
# sanity checking on parameters: if --socketpath is used, and --port or
341
 
# --ssl-port is NOT specified, it means that we're using UNIX domain sockets,
342
 
# none of the IP params are allowed. The code would probably work ok if we
343
 
# didn't check it, but it's better if we detect the error and report it lest
344
 
# the admin find surprises.
345
 
 
346
 
my $listen_unix = 1;
347
 
my $listen_inet = 1;
348
 
my $listen_ssl  = 0;
349
 
if (!defined $opt{'socketpath'}) {
350
 
  $listen_unix = 0;
351
 
} else {
352
 
  $listen_inet = 0;
353
 
}
354
 
 
355
 
if (
356
 
  ( @{ $opt{'allowed-ip'} } > 0 )
357
 
    or defined $opt{'auth-ident'}
358
 
    or defined $opt{'port'}
359
 
  )
360
 
{
361
 
  $listen_inet = 1;
362
 
}
363
 
 
364
 
if (
365
 
    defined $opt{'ssl'}
366
 
    or defined $opt{'ssl-port'}
367
 
    or defined $opt{'ssl-version'}
368
 
  )
369
 
{
370
 
  $listen_ssl = 1;
371
 
  if (!defined $opt{'ssl-port'}) {
372
 
    $listen_inet = 0;
373
 
  }
374
 
}
375
 
 
376
 
if (
377
 
  !$opt{'socketpath'}
378
 
  and ( $opt{'socketowner'}
379
 
    or $opt{'socketgroup'}
380
 
    or $opt{'socketmode'})
381
 
  )
382
 
{
383
 
  print_usage_and_exit("ERROR: --socketowner/group/mode requires --socketpath param");
 
485
  # rel2abs taints the new value!
 
486
  $opt{$opt} =
 
487
    untaint_file_path(File::Spec->rel2abs( $opt{$opt} )) if $opt{$opt};
384
488
}
385
489
 
386
490
# These can be changed on command line with -A flag
387
 
# but only if we're not using UNIX domain sockets
388
491
my $allowed_nets = Mail::SpamAssassin::NetSet->new();
389
 
if ( not defined $opt{'socketpath'} ) {
390
 
  if ( @{ $opt{'allowed-ip'} } ) {
391
 
    set_allowed_ip( grep length, map { split /,/ } @{ $opt{'allowed-ip'} } );
392
 
  }
393
 
  else {
394
 
    set_allowed_ip('127.0.0.1'); #, '::1'); M::SA::NetSet needs fixing for IPv6
395
 
  }
 
492
if ( @{ $opt{'allowed-ip'} } ) {
 
493
  set_allowed_ip( grep length, map { split /,/ } @{ $opt{'allowed-ip'} } );
 
494
} else {
 
495
  set_allowed_ip('127.0.0.1', '::1');
396
496
}
397
497
 
398
498
# ident-based spamc user authentication
399
499
if ( $opt{'auth-ident'} ) {
400
 
  eval { require Net::Ident };
401
 
  die "spamd: ident-based authentication requested, but Net::Ident is unavailable ($@)\n"
402
 
    if ($@);
 
500
  eval { require Net::Ident }
 
501
  or die "spamd: ident-based authentication requested, ".
 
502
         "but Net::Ident is unavailable: $@\n";
403
503
 
404
504
  $opt{'ident-timeout'} = undef if $opt{'ident-timeout'} <= 0.0;
405
505
  import Net::Ident qw(ident_lookup);
406
506
}
407
507
 
408
 
# Check for server certs
409
 
$opt{'server-key'}  ||= "$LOCAL_RULES_DIR/certs/server-key.pem";
410
 
$opt{'server-cert'} ||= "$LOCAL_RULES_DIR/certs/server-cert.pem";
411
 
if ( $listen_ssl ) {
412
 
  eval { require IO::Socket::SSL };
413
 
  die "spamd: SSL encryption requested, but IO::Socket::SSL is unavailable ($@)\n"
414
 
    if ($@);
415
 
 
416
 
  if ( !-e $opt{'server-key'} ) {
417
 
    die "spamd: server key file $opt{'server-key'} does not exist\n";
418
 
  }
419
 
  if ( !-e $opt{'server-cert'} ) {
420
 
    die "spamd: server certificate file $opt{'server-cert'} does not exist\n";
421
 
  }
422
 
}
423
 
 
424
508
### Begin initialization of logging ########################
425
509
 
426
510
# The syslog facility can be changed on the command line with the
588
672
my $timeout_child;        # processing timeout (headers->finish), 0=no timeout
589
673
my $clients_per_child;    # number of clients each child should process
590
674
my %children;             # current children
 
675
my @children_exited;
591
676
 
592
677
if ( defined $opt{'max-children'} ) {
593
678
  $childlimit = $opt{'max-children'};
657
742
 
658
743
# Do whitelist later in tmp dir. Side effect: this will be done as -u user.
659
744
 
660
 
my ( $sslport, $sslversion, $inetport, $addr, $proto );
661
 
 
662
 
if ( $listen_inet || $listen_ssl ) {
663
 
  $proto = getprotobyname('tcp') or die "getprotobyname(tcp): $!";
664
 
 
665
 
  $addr = $opt{'listen-ip'};
666
 
  if (defined $addr) {
667
 
    if ($addr ne '') {
668
 
      $addr = ip_or_name_to_ip($addr);
669
 
      die "spamd: invalid address: $opt{'listen-ip'}\n" unless $addr;
670
 
    }
671
 
    else {
672
 
      $addr = '0.0.0.0';    # FIXME: this won't bind to IPv6 sockets
673
 
    }
674
 
  }
675
 
  else {
676
 
    $addr = '127.0.0.1';
677
 
  }
678
 
}
 
745
my $sslversion = $opt{'ssl-version'} || 'sslv3';
 
746
if ($sslversion !~ /^(?:sslv3|tlsv1)$/) {
 
747
  die "spamd: invalid ssl-version: $opt{'ssl-version'}\n";
 
748
}
 
749
 
 
750
$opt{'server-key'}  ||= "$LOCAL_RULES_DIR/certs/server-key.pem";
 
751
$opt{'server-cert'} ||= "$LOCAL_RULES_DIR/certs/server-cert.pem";
 
752
 
 
753
# ---------------------------------------------------------------------------
 
754
# Server (listening) socket setup for the various supported types
 
755
 
 
756
dbg("spamd: socket module of choice: %s %s, Socket %s".
 
757
    ", %s PF_INET, %s PF_INET6, %s, AI_ADDRCONFIG %s",
 
758
    $io_socket_module_name,
 
759
    $io_socket_module_name->VERSION,
 
760
    Socket->VERSION,
 
761
    $have_inet4 ? 'have' : 'no',
 
762
    $have_inet6 ? 'have' : 'no',
 
763
    $have_getaddrinfo_in_core ? 'using Socket::getaddrinfo'
 
764
    : $have_getaddrinfo_legacy ? 'using legacy Socket6::getaddrinfo'
 
765
    : 'no getaddrinfo, using gethostbyname, IPv4-only',
 
766
    $ai_addrconfig_flag ? "is supported" : "not supported",
 
767
);
 
768
 
 
769
my $have_ssl_module;
 
770
my @listen_sockets;  # list of hashrefs, contains info on all listen sockets
 
771
my $server_select_mask;
 
772
 
 
773
my @listen_socket_specs = @{$opt{'listen-sockets'}};
 
774
 
 
775
{ # merge legacy option --socketpath into @listen_socket_specs
 
776
  my $socketpath = $opt{'socketpath'};
 
777
  if (defined $socketpath && $socketpath ne '') {
 
778
    $socketpath =~ m{^/}
 
779
      or die "socketpath option should specify an absolute path: $socketpath";
 
780
    push(@listen_socket_specs, $socketpath);
 
781
  }
 
782
}
 
783
 
 
784
# supply a default socket (loopback IP address) if none specified
 
785
push(@listen_socket_specs, 'localhost')  if !@listen_socket_specs;
 
786
 
 
787
for (@listen_socket_specs) {
 
788
  my $socket_specs = $_;
 
789
 
 
790
  $socket_specs = '*'  if $socket_specs eq '';  # empty implies all interfaces
 
791
 
 
792
  local($1,$2,$3,$4,$5,$6);
 
793
  if ($socket_specs =~
 
794
           m{^ (?: (ssl) : )?
 
795
               ( / .* ) \z }xsi) {  # unix socket - absolute path
 
796
    my($proto,$path) = ($1, $2);
 
797
  # $proto = 'ssl'  if defined $opt{'ssl'} || defined $opt{'ssl-port'};
 
798
    $proto = !defined($proto) ? '' : lc($proto);
 
799
    # abstracted out the setup-retry code
 
800
    dbg("spamd: unix socket: %s", $path);
 
801
    server_sock_setup(\&server_sock_setup_unix, $socket_specs, $path);
 
802
 
 
803
  } elsif ($socket_specs =~
 
804
           m{^ (?: (ssl) : )?
 
805
               (?: \[ ( [^\]]* ) \]
 
806
                 | ( [a-z0-9._-]* )
 
807
                 | ( [a-f0-9]* : [a-f0-9]* : [a-f0-9:]* \z )
 
808
                 | ( \* )
 
809
               )?
 
810
               (?: : ( [a-z0-9-]* ) )? \z }xsi) {
 
811
    my($proto,$addr,$port) = ($1, $2||$3||$4||$5, $6);
 
812
    $addr = 'localhost'  if !defined $addr;
 
813
    $proto = 'ssl'  if defined $opt{'ssl'} || defined $opt{'ssl-port'};
 
814
    $proto = !defined($proto) ? '' : lc($proto);
 
815
    $port = $opt{'ssl-port'}  if !defined $port && $proto eq 'ssl';
 
816
    $port = $opt{'port'}      if !defined $port || $port eq '';
 
817
    $port = '783'             if !defined $port || $port eq '';
 
818
    if ($port ne '' && $port !~ /^(\d+)\z/) {
 
819
      $port = ( getservbyname($port,'tcp') )[2];
 
820
      $port or die "spamd: invalid port: $port, socket: $socket_specs\n";
 
821
    }
 
822
    # abstracted out the setup-retry code
 
823
    dbg('spamd: %s socket specification: "%s", IP address: %s, port: %s',
 
824
        $proto, $socket_specs, $addr, $port);
 
825
    server_sock_setup(\&server_sock_setup_inet,
 
826
                      $socket_specs, $addr, $port, $proto eq 'ssl' ? 1 : 0);
 
827
  } else {
 
828
    die "Invalid socket specification syntax: $socket_specs\n";
 
829
  }
 
830
}
 
831
 
 
832
@listen_sockets  or die "No listen sockets specified, aborting\n";
 
833
 
 
834
# ---------------------------------------------------------------------------
 
835
 
 
836
# Check for server certs
 
837
if ( $have_ssl_module ) {
 
838
  if ( !-e $opt{'server-key'} ) {
 
839
    die "spamd: server key file $opt{'server-key'} does not exist\n";
 
840
  }
 
841
  if ( !-e $opt{'server-cert'} ) {
 
842
    die "spamd: server certificate file $opt{'server-cert'} does not exist\n";
 
843
  }
 
844
}
 
845
 
 
846
# ---------------------------------------------------------------------------
 
847
 
 
848
my $sockets_access_lock_tempfile;  # a File::Temp object, if locking is needed
 
849
my $sockets_access_lock_fh;  # per-child file handle on a lock file
679
850
 
680
851
my $backchannel = Mail::SpamAssassin::SubProcBackChannel->new();
681
852
my $scaling;
 
853
 
682
854
if (!$opt{'round-robin'})
683
855
{
684
856
  my $max_children = $childlimit;
689
861
  if ($childlimit > $opt{'max-spare'}) {
690
862
    $childlimit = $opt{'max-spare'};
691
863
  }
 
864
  if ($childlimit < $opt{'min-children'}) {
 
865
    $childlimit = $opt{'min-children'};
 
866
  }
692
867
 
693
868
  $scaling = Mail::SpamAssassin::SpamdForkScaling->new({
694
869
        backchannel => $backchannel,
702
877
 
703
878
# ---------------------------------------------------------------------------
704
879
 
705
 
my $listeninfo = compose_listen_info_string();
706
 
 
707
880
sub compose_listen_info_string {
708
881
  my @listeninfo;
709
882
 
710
 
  if ( $listen_unix ) {
711
 
    push @listeninfo, "UNIX domain socket " . $opt{'socketpath'};
712
 
  }
713
 
 
714
 
  if ( $listen_ssl ) {
715
 
    $sslport = $opt{'ssl-port'} || $opt{'port'} || 783;
716
 
    if ($sslport !~ /^(\d+)$/ ) {
717
 
      $sslport = ( getservbyname($sslport, 'tcp') )[2];
718
 
      die "spamd: invalid ssl-port: $opt{'port'}\n" unless $sslport;
719
 
    }
720
 
    $sslversion = $opt{'ssl-version'} || 'sslv23';
721
 
    if ($sslversion !~ /^(?:sslv([23]|23)|(tlsv1))$/) {
722
 
      die "spamd: invalid ssl-version: $opt{'ssl-version'}\n";
723
 
    }
724
 
 
725
 
    push @listeninfo, "SSL port $sslport/tcp";
726
 
    push @listeninfo, "SSL version $sslversion";
727
 
  }
728
 
 
729
 
  if ( $listen_inet ) {
730
 
    $inetport = $opt{'port'} || 783;
731
 
    if ($inetport !~ /^(\d+)$/ ) {
732
 
      $inetport = ( getservbyname($inetport, 'tcp') )[2];
733
 
      die "spamd: invalid port: $opt{'port'}\n" unless $inetport;
734
 
    }
735
 
 
736
 
    push @listeninfo, "port $inetport/tcp";
 
883
  for my $socket_info (@listen_sockets) {
 
884
    next if !$socket_info;
 
885
    my $socket = $socket_info->{socket};
 
886
    next if !$socket;
 
887
    my $socket_specs = $socket_info->{specs};
 
888
 
 
889
    if ($socket->isa('IO::Socket::UNIX')) {
 
890
      push(@listeninfo, "UNIX domain socket " . $socket_info->{path});
 
891
 
 
892
    } elsif ( $socket->isa('IO::Socket::INET')  ||
 
893
              $socket->isa('IO::Socket::INET6') ||
 
894
              $socket->isa('IO::Socket::IP') ) {
 
895
      push(@listeninfo, sprintf("%s [%s]:%s", ref $socket,
 
896
                      $socket_info->{ip_addr}, $socket_info->{port}));
 
897
 
 
898
    } elsif ($socket->isa('IO::Socket::SSL')) {
 
899
      push(@listeninfo, sprintf("SSL [%s]:%s, ssl version %s",
 
900
                      $socket_info->{ip_addr}, $socket_info->{port},
 
901
                      $opt{'ssl-version'}||'sslv3'));
 
902
    }
737
903
  }
738
904
 
739
905
  # just for reporting at startup
740
 
  $listeninfo = join ', ', @listeninfo;
741
 
}
742
 
 
743
 
# ---------------------------------------------------------------------------
744
 
# Server (listening) socket setup for the various supported types
745
 
 
746
 
my ( $server_inet, $server_unix, $server_ssl );
747
 
my ( $fd_inet, $fd_unix, $fd_ssl );
748
 
my $have_multiple_server_socks;
749
 
my $server_select_mask;
750
 
 
751
 
# abstract out the setup-retry code
752
 
if ( $listen_unix ) {
753
 
  server_sock_setup(sub { server_sock_setup_unix(); });
754
 
}
755
 
if ( $listen_ssl ) {
756
 
  server_sock_setup(sub { server_sock_setup_ssl(); });
757
 
}
758
 
if ( $listen_inet ) {
759
 
  server_sock_setup(sub { server_sock_setup_inet(); });
 
906
  return join(', ', @listeninfo);
760
907
}
761
908
 
762
909
sub server_sock_setup {
763
 
  my $sub = shift;
 
910
  my($sub, @args) = @_;
764
911
 
765
912
  # retry 3 times to bind to the listening socket; 3 seconds delay,
766
913
  # max, but should allow a little time for any existing shutting-down
769
916
  for my $retry (1 .. $lastretry) {
770
917
    if ($retry > 1) { sleep 1; }
771
918
 
772
 
    eval { $sub->(); };
773
 
    last unless ($@);       # success => break
 
919
    eval { &$sub(@args) } and last;  # success => break
774
920
 
775
921
    if ($retry == $lastretry) {
776
922
      die $@;               # this is fatal
785
931
 
786
932
# Create the sockets
787
933
sub server_sock_setup_unix {
788
 
  my $path = $opt{'socketpath'};
 
934
  my($socket_specs, $path) = @_;
789
935
 
790
936
  # see if the socket is in use: if we connect to the current socket, it
791
937
  # means that spamd is already running, so we have to bail on our own.
797
943
      die "spamd: file $path exists but is no socket, exiting\n";
798
944
    }
799
945
  
800
 
    if ( new IO::Socket::UNIX( Peer => $path, Type => SOCK_STREAM ) ) {
801
 
      # we connected successfully: must alreadybe running
802
 
 
803
 
      undef $opt{'socketpath'};    # so exit handlers won't unlink it!
804
 
 
 
946
    if ( IO::Socket::UNIX->new( Peer => $path, Type => &SOCK_STREAM ) ) {
 
947
      # socket bind successful: must already be running
 
948
 
 
949
      # make sure not to enter this socket into @listen_sockets,
 
950
      # otherwise exit handlers would unlink it!
805
951
      die "spamd: already running on $path, exiting\n";
806
952
    }
807
953
    else {
815
961
 
816
962
  my %socket = (
817
963
    Local  => $path,
818
 
    Type   => SOCK_STREAM,
819
 
    Listen => SOMAXCONN,
 
964
    Type   => &SOCK_STREAM,
 
965
    Listen => &SOMAXCONN,
820
966
  );
821
967
  dbg("spamd: creating UNIX socket:\n" . join("\n", map { " $_: " . (defined $socket{$_} ? $socket{$_} : "(undef)") } sort keys %socket));
822
 
  $server_unix = IO::Socket::UNIX->new(%socket);
 
968
  my $server_unix = IO::Socket::UNIX->new(%socket);
823
969
  
824
970
  # sanity check!  cf. bug 3490
825
971
  if (not $server_unix or not -S $path) {
868
1014
  if (!chmod $mode, $path) {    # make sure everybody can talk to it
869
1015
    die "spamd: could not chmod $path to $mode: $!";
870
1016
  }
871
 
}
872
1017
 
873
 
sub server_sock_setup_ssl {
874
 
  my %socket = (
875
 
    LocalAddr       => $addr,
876
 
    LocalPort       => $sslport,
877
 
    Proto           => $proto,
878
 
    Type            => SOCK_STREAM,
879
 
    ReuseAddr       => 1,
880
 
    Listen          => SOMAXCONN,
881
 
    SSL_version     => $sslversion,
882
 
    SSL_verify_mode => 0x00,
883
 
    SSL_key_file    => $opt{'server-key'},
884
 
    SSL_cert_file   => $opt{'server-cert'}
885
 
  );
886
 
  dbg("spamd: creating SSL socket:\n" . join("\n", map { " $_:  " . (defined $socket{$_} ? $socket{$_} : "(undef)") } sort keys %socket));
887
 
  $server_ssl = new IO::Socket::SSL(%socket)
888
 
       || die "spamd: could not create SSL socket on $addr:$sslport: $!\n";
 
1018
  push(@listen_sockets, { specs => $socket_specs,
 
1019
                          path => $path,
 
1020
                          socket => $server_unix,
 
1021
                          fd => $server_unix->fileno })  if $server_unix;
 
1022
  1;
889
1023
}
890
1024
 
891
1025
sub server_sock_setup_inet {
892
 
  my %socket = (
893
 
    LocalAddr => $addr,
894
 
    LocalPort => $inetport,
895
 
    Proto     => $proto,
896
 
    Type      => SOCK_STREAM,
897
 
    ReuseAddr => 1,
898
 
    Listen    => SOMAXCONN
899
 
  );
900
 
  dbg("spamd: creating INET socket:\n" . join("\n", map { " $_: " . (defined $socket{$_} ? $socket{$_} : "(undef)") } sort keys %socket));
901
 
  $server_inet = new_io_socket_inetx(%socket)
902
 
       || die "spamd: could not create INET socket on $addr:$inetport: $!\n";
 
1026
  my($socket_specs, $addr, $port, $ssl) = @_;
 
1027
 
 
1028
  $have_inet4 || $have_inet6
 
1029
    or warn "spamd: neither the PF_INET (IPv4) nor the PF_INET6 (IPv6) ".
 
1030
            "protocol families seem to be available, pushing our luck anyway\n";
 
1031
 
 
1032
  my $ai_family = &AF_UNSPEC;  # defaults to any address family (i.e. both)
 
1033
  if      ($have_inet6 && (!$have_inet4 || $opt{'force_ipv6'})) {
 
1034
    $ai_family = &AF_INET6;
 
1035
  } elsif ($have_inet4 && (!$have_inet6 || $opt{'force_ipv4'})) {
 
1036
    $ai_family = &AF_INET;
 
1037
  }
 
1038
  my($error, @addresses);
 
1039
  if (!defined $addr || lc $addr eq 'localhost') {  # loopback interface
 
1040
    push(@addresses, '127.0.0.1')
 
1041
      if $ai_family == &AF_UNSPEC || $ai_family == &AF_INET;
 
1042
    push(@addresses, '::1')
 
1043
      if $ai_family == &AF_UNSPEC || $ai_family == &AF_INET6;
 
1044
  } elsif ($addr eq '*' || $addr eq '') {  # any address
 
1045
    push(@addresses, '0.0.0.0')
 
1046
      if $ai_family == &AF_UNSPEC || $ai_family == &AF_INET;
 
1047
    push(@addresses, '::')
 
1048
      if $ai_family == &AF_UNSPEC || $ai_family == &AF_INET6;
 
1049
  } else {
 
1050
    ($error, @addresses) = ip_or_name_to_ip_addresses($addr, $ai_family);
 
1051
  }
 
1052
  die "spamd: invalid address for a listen socket: \"$socket_specs\": $error\n"
 
1053
    if $error;
 
1054
  die "spamd: no valid address for a listen socket: \"$socket_specs\"\n"
 
1055
    if !@addresses;
 
1056
 
 
1057
  dbg("spamd: attempting to listen on IP addresses: %s, port %d",
 
1058
      join(', ',@addresses), $port);
 
1059
  for my $adr (@addresses) {
 
1060
    my %sockopt = (
 
1061
      LocalAddr => $adr,
 
1062
      LocalPort => $port,
 
1063
      Type      => &SOCK_STREAM,
 
1064
      Proto     => 'tcp',
 
1065
      ReuseAddr => 1,
 
1066
      Listen    => &SOMAXCONN,
 
1067
    );
 
1068
    $sockopt{V6Only} = 1  if $io_socket_module_name eq 'IO::Socket::IP'
 
1069
                             && IO::Socket::IP->VERSION >= 0.09;
 
1070
    %sockopt = (%sockopt, (
 
1071
      SSL_version     => $sslversion,
 
1072
      SSL_verify_mode => 0x00,
 
1073
      SSL_key_file    => $opt{'server-key'},
 
1074
      SSL_cert_file   => $opt{'server-cert'},
 
1075
    ))  if $ssl;
 
1076
    dbg("spamd: creating %s socket: %s",
 
1077
        $ssl ? 'IO::Socket::SSL' : $io_socket_module_name,
 
1078
        join(', ', map("$_: ".(defined $sockopt{$_} ? $sockopt{$_} : "(undef)"),
 
1079
                       sort keys %sockopt)));
 
1080
    if ($ssl && !$have_ssl_module) {
 
1081
      eval { require IO::Socket::SSL }
 
1082
        or die "spamd: SSL encryption requested, ".
 
1083
               "but IO::Socket::SSL is unavailable ($@)\n";
 
1084
      $have_ssl_module = 1;
 
1085
    }
 
1086
    my $server_inet = $ssl ? IO::Socket::SSL->new(%sockopt)
 
1087
                           : $io_socket_module_name->new(%sockopt);
 
1088
    $server_inet
 
1089
      or die sprintf("spamd: could not create %s socket on [%s]:%s: %s\n",
 
1090
                     $ssl ? 'IO::Socket::SSL' : $io_socket_module_name,
 
1091
                     $adr, $port, $!);
 
1092
    push(@listen_sockets, { specs => $socket_specs,
 
1093
                            ip_addr => $adr, port => $port,
 
1094
                            socket => $server_inet,
 
1095
                            fd => $server_inet->fileno }) if $server_inet;
 
1096
  }
 
1097
  1;
903
1098
}
904
1099
 
905
1100
# ---------------------------------------------------------------------------
907
1102
# for select() purposes: make a map of the server socket FDs
908
1103
map_server_sockets();
909
1104
 
 
1105
if (!$scaling && @listen_sockets > 1) {
 
1106
  require File::Temp;
 
1107
 
 
1108
  # Have multiple sockets and autonomous child processes (--round-robin),
 
1109
  # prepare an anonymous lock file to protect access to select+accept.
 
1110
 
 
1111
  # using the same choice of a tmp dir as in Util::secure_tmpfile()
 
1112
  my $tmpdir = untaint_file_path($ENV{'TMPDIR'} || File::Spec->tmpdir);
 
1113
 
 
1114
  # the file will be automatically removed by DESTROY on program exit
 
1115
  $sockets_access_lock_tempfile =
 
1116
    File::Temp->new(DIR => $tmpdir, SUFFIX => '.lck', EXLOCK => 0);
 
1117
 
 
1118
  dbg("spamd: created a lock file %s to protect select+accept",
 
1119
      $sockets_access_lock_tempfile->filename);
 
1120
}
 
1121
 
910
1122
if ( defined $opt{'pidfile'} ) {
911
 
  $opt{'pidfile'} =
912
 
    Mail::SpamAssassin::Util::untaint_file_path( $opt{'pidfile'} );
 
1123
  $opt{'pidfile'} = untaint_file_path( $opt{'pidfile'} );
913
1124
}
914
1125
 
915
1126
 
924
1135
    debug                => ( $opt{'debug'} || 0 ),
925
1136
    paranoid             => ( $opt{'paranoid'} || 0 ),
926
1137
    require_rules        => 1,
 
1138
    skip_prng_reseeding  => 1,  # let us do the reseeding by ourselves
927
1139
    home_dir_for_helpers => (
928
1140
      defined $opt{'home_dir_for_helpers'}
929
1141
      ? $opt{'home_dir_for_helpers'}
943
1155
  $copy_config_p = 0;
944
1156
}
945
1157
 
 
1158
# See Bug 6837: establishing a __DIE__ handler should be done after
 
1159
# most modules have been loaded, as the $^S cannot distinguish
 
1160
# true failures from eval attempt failures within a 'require'-d module.
 
1161
# If the problem persists in some late-lodaded modules, we may need
 
1162
# to tighten the condition to something like 'if defined $^S && !$^S'.
 
1163
#
 
1164
# redirect __WARN__ and __DIE__
 
1165
# do not trap warnings here based on eval scope; evals are very
 
1166
# common throughout.  die()s can be trapped though.
 
1167
$SIG{__WARN__} = sub {
 
1168
  log_message("warn", $_[0]);
 
1169
};
 
1170
$SIG{__DIE__} = sub {
 
1171
  # see http://use.perl.org/comments.pl?mode=flat&sid=33872 for $^S
 
1172
  log_message("error", $_[0]) unless $^S;
 
1173
};
 
1174
 
946
1175
## DAEMONIZE! ##
947
1176
 
948
1177
my $originalparent = $$;
988
1217
# log server started, but processes watching the log to wait for connect
989
1218
# should wait until they see the pid, after signal handlers are in place
990
1219
# FIXME: two calls are one too much
991
 
info("spamd: server started on $listeninfo (running version "
992
 
     . Mail::SpamAssassin::Version() . ")" );
 
1220
info("spamd: server started on %s (running version %s)",
 
1221
     compose_listen_info_string(), Mail::SpamAssassin::Version());
993
1222
 
994
1223
my $remote_port;
995
1224
 
1004
1233
  }
1005
1234
}
1006
1235
 
 
1236
# The "prefork_init" plugin callback is called in the parent process shortly
 
1237
# before forking off child processes. It allows plugins which were activated
 
1238
# by the master spamd process to prepare for a fork, e.g. by closing or
 
1239
# dropping some resources which won't be of any use by a child process.
 
1240
#
 
1241
$spamtest->call_plugins("prefork_init");  # since SA 3.4.0
 
1242
 
1007
1243
# now allow waiting processes to connect, if they're watching the log.
1008
1244
# The test suite does this!
1009
 
info("spamd: server pid: $$\n");
 
1245
info("spamd: server pid: $$");
1010
1246
kill("USR1",$originalparent) if ($opt{'daemonize'});
1011
1247
 
1012
1248
# Fork off our children.
1015
1251
}
1016
1252
 
1017
1253
if ($scaling) {
1018
 
  $scaling->set_server_fh($server_inet, $server_unix, $server_ssl);
 
1254
  $scaling->set_server_fh(map($_->{socket},@listen_sockets));
1019
1255
}
1020
1256
 
1021
1257
while (1) {
1031
1267
# child_handler()  if !$scaling || am_running_on_windows();
1032
1268
  child_handler();  # it doesn't hurt to call child_handler unconditionally
1033
1269
 
 
1270
  child_cleaner();
 
1271
 
1034
1272
  do_sighup_restart()  if defined $got_sighup;
1035
1273
 
1036
1274
  for (my $i = keys %children; $i < $childlimit; $i++) {
1082
1320
        or die "spamd: cannot unblock SIGINT/SIGCHLD for fork: $!\n";
1083
1321
    }
1084
1322
 
 
1323
    srand;  # reseed pseudorandom number generator soon for each child process
1085
1324
    $spamtest->call_plugins("spamd_child_init");
1086
1325
 
 
1326
    if ($sockets_access_lock_tempfile) {
 
1327
      # A lock will be required across select+accept in a child processes,
 
1328
      # Bug 6996. Need to have a per-child filehandle on the same lock file
 
1329
      # for flock to work, let's dup(2) the parent's file handle.
 
1330
      my $fname = $sockets_access_lock_tempfile->filename;
 
1331
      $sockets_access_lock_fh = IO::File->new($fname, "+>");
 
1332
      $sockets_access_lock_fh or die "Can't open a lock file $fname: $!";
 
1333
    }
 
1334
 
1087
1335
    # support non-root use
1088
1336
    if ( $opt{'username'} ) {
1089
1337
      my ( $uuid, $ugid ) = ( getpwnam( $opt{'username'} ) )[ 2, 3 ];
1131
1379
 
1132
1380
      # use a large eval scope to catch die()s and ensure they
1133
1381
      # don't kill the server.
1134
 
      my $evalret = eval { accept_a_conn(); };
 
1382
      my $evalret = eval { accept_a_conn($scaling ? 0.5 : undef); };
1135
1383
 
1136
 
      if (!defined ($evalret)) {
 
1384
      if (!defined $evalret) {
1137
1385
        warn("spamd: error: $@ $!, continuing");
1138
1386
        if ($client) { $client->close(); }  # avoid fd leaks
1139
1387
      }
1194
1442
}
1195
1443
 
1196
1444
sub accept_from_any_server_socket {
1197
 
 
1198
 
  my $fdvec = $server_select_mask;
1199
 
 
1200
 
  if ($have_multiple_server_socks) {
1201
 
    # determine which of our server FDs is ready using select().
1202
 
    # We only need to do this if we have more than one server
1203
 
    # socket supported, since otherwise there can only be one socket
1204
 
    # with a client waiting.
1205
 
    # (TODO: we could extend the prefork protocol to pass this data)
1206
 
    my $nfound = select($fdvec, undef, undef, 0.1);
1207
 
    die "oops? accept_a_conn: no fds ready" unless $nfound;
1208
 
  }
1209
 
 
1210
 
  if ($fd_inet && vec $fdvec, $fd_inet, 1) {
1211
 
    $client = $server_inet->accept;
1212
 
  }
1213
 
  elsif ($fd_unix && vec $fdvec, $fd_unix, 1) {
1214
 
    $client = $server_unix->accept;
1215
 
  }
1216
 
  elsif ($fd_ssl && vec $fdvec, $fd_ssl, 1) {
1217
 
    $client = $server_ssl->accept;
1218
 
  }
1219
 
  else {
1220
 
    die "accept_a_conn: no fds ready by vec: $fdvec";
1221
 
  }
1222
 
  return $client;
 
1445
  my($timeout) = @_;
 
1446
  my($client, $selected_socket_info, $socket, $locked);
 
1447
 
 
1448
  eval {
 
1449
    if (!@listen_sockets) {
 
1450
      # nothing?
 
1451
      die "no sockets?";
 
1452
 
 
1453
    } elsif (@listen_sockets == 1) {
 
1454
      $selected_socket_info = $listen_sockets[0];
 
1455
 
 
1456
    } else {
 
1457
      # determine which of our server FDs is ready using select().
 
1458
      # We only need to do this if we have more than one server
 
1459
      # socket supported, since otherwise there can only be one socket
 
1460
      # with a client waiting.
 
1461
      # (TODO: we could extend the prefork protocol to pass this data)
 
1462
 
 
1463
      if ($sockets_access_lock_fh) {
 
1464
        dbg("spamd: acquiring a lock over select+accept");
 
1465
        # with multipe sockets a lock across select+accept is needed, Bug 6996
 
1466
        flock($sockets_access_lock_fh, LOCK_EX)
 
1467
          or die "Can't acquire lock access to sockets: $!";
 
1468
        $locked = 1;
 
1469
      }
 
1470
 
 
1471
      my $sel_mask_str = unpack('b*', $server_select_mask);
 
1472
      dbg("spamd: select() on fd bit field %s, %s, %s",
 
1473
          $sel_mask_str, defined $timeout ? "timeout $timeout" : "no timeout",
 
1474
          $locked ? "locked" : "not locked");
 
1475
 
 
1476
      my $fdvec = $server_select_mask;
 
1477
      my $nfound = select($fdvec, undef, undef, $timeout);
 
1478
 
 
1479
      if (!defined $nfound || $nfound < 0) {
 
1480
        die "select failed on fd bit field $sel_mask_str: $!";
 
1481
      } elsif (!$nfound) {
 
1482
        die "no fd ready, fd bit field $sel_mask_str";
 
1483
      }
 
1484
 
 
1485
      my(@ready_fd) =  # list of file desciptors ready for read
 
1486
        grep(defined $_->{fd} && vec($fdvec, $_->{fd}, 1), @listen_sockets);
 
1487
      if (!@ready_fd) {
 
1488
        die "no file descriptors matching a bit field " . unpack('b*',$fdvec);
 
1489
      } elsif (@ready_fd == 1) {  # easy, just one is ready
 
1490
        $selected_socket_info = $ready_fd[0];
 
1491
      } else {  # give equal opportunity to each ready socket
 
1492
        my $j = int rand(@ready_fd);
 
1493
        $selected_socket_info = $ready_fd[$j];
 
1494
        dbg("spamd: requests ready on multiple sockets, picking #%d out of %d",
 
1495
            $j+1, scalar @ready_fd);
 
1496
      }
 
1497
 
 
1498
    } # end multiple sockets case
 
1499
 
 
1500
    if ($selected_socket_info) {
 
1501
      my $socket = $selected_socket_info->{socket};
 
1502
      $socket or die "no socket???, impossible";
 
1503
      dbg("spamd: accept() on fd %d", $selected_socket_info->{fd});
 
1504
      $client = $socket->accept;
 
1505
    }
 
1506
    1;  # end eval with success
 
1507
 
 
1508
  } or do {
 
1509
    my $err = $@ ne '' ? $@ : "errno=$!";  chomp $err;
 
1510
    if ($locked) {
 
1511
      dbg("spamd: releasing a lock over select+accept");
 
1512
      flock($sockets_access_lock_fh, LOCK_UN)
 
1513
        or die "Can't release sockets-access lock: $!";
 
1514
      $locked = 0;
 
1515
    }
 
1516
    die "accept_a_conn: $err";
 
1517
  };
 
1518
 
 
1519
  if ($locked) {
 
1520
    dbg("spamd: releasing a lock over select+accept");
 
1521
    flock($sockets_access_lock_fh, LOCK_UN)
 
1522
      or die "Can't release sockets-access lock: $!";
 
1523
  }
 
1524
  $client or die sprintf("accept_a_conn: %s accept failed: %s",
 
1525
                         ref $socket,
 
1526
                         !$socket->isa('IO::Socket::SSL') ? $!
 
1527
                           : $socket->errstr.", $!");
 
1528
  return ($client, $selected_socket_info);
1223
1529
}
1224
1530
 
1225
1531
sub accept_a_conn {
1226
 
  $client = accept_from_any_server_socket();
 
1532
  my ($timeout) = @_;
 
1533
 
 
1534
  my $socket_info;
 
1535
  # $client is a global variable
 
1536
  ($client, $socket_info) = accept_from_any_server_socket($timeout);
1227
1537
 
1228
1538
  if ($scaling) {
1229
1539
    $scaling->update_child_status_busy();
1237
1547
    if ( $! == &Errno::EINTR ) {
1238
1548
      return 0;
1239
1549
    }
1240
 
    elsif ( $! == 0 && $listen_ssl ) {
1241
 
      warn("spamd: SSL failure: " . &IO::Socket::SSL::errstr());
1242
 
      return 0;
1243
 
    }
1244
1550
    else {
1245
1551
      warn("spamd: accept failed: $!");
1246
1552
      return -1;
1253
1559
  $spamtest->timer_reset;
1254
1560
  my $start = time;
1255
1561
 
1256
 
  my ($remote_hostname, $remote_hostaddr);
1257
 
  if ($opt{'socketpath'}) {
 
1562
  my ($remote_hostname, $remote_hostaddr, $local_port);
 
1563
 
 
1564
  if ($client->isa('IO::Socket::UNIX')) {
1258
1565
    $remote_hostname = 'localhost';
1259
1566
    $remote_hostaddr = '127.0.0.1';
1260
 
    $remote_port = $opt{'socketpath'};
1261
 
    info("spamd: got connection over " . $opt{'socketpath'});
 
1567
    $remote_port = $socket_info->{path};
 
1568
    info("spamd: got connection over %s", $socket_info->{path});
1262
1569
  }
1263
1570
  else {
1264
 
    ($remote_port, $remote_hostaddr, $remote_hostname) =
1265
 
      peer_info_from_socket($client)
1266
 
      or die 'failed to obtain port and ip from socket';
 
1571
    ($remote_port, $remote_hostaddr, $remote_hostname, $local_port) =
 
1572
      peer_info_from_socket($client);
 
1573
    $remote_hostaddr or die 'failed to obtain port and ip from socket';
1267
1574
 
1268
 
    my $msg = "connection from ${remote_hostname} [${remote_hostaddr}] at port ${remote_port}";
 
1575
    my $msg = sprintf("connection from %s [%s]:%s to port %d, fd %d",
 
1576
                      $remote_hostname, $remote_hostaddr, $remote_port,
 
1577
                      $local_port, $socket_info->{fd});
1269
1578
    if (ip_is_allowed($remote_hostaddr)) {
1270
1579
      info("spamd: $msg");
1271
1580
    }
2139
2448
      am_running_on_windows() ? ('nobody') : getpwnam($suidto);
2140
2449
 
2141
2450
  if (!defined $uid) {
2142
 
      my $errmsg = "spamd: handle_user unable to find user: '$suidto'\n";
2143
 
      die $errmsg if $spamtest->{'paranoid'};
 
2451
      my $errmsg =
 
2452
        "spamd: handle_user (getpwnam) unable to find user: '$suidto'";
 
2453
      die "$errmsg\n" if $spamtest->{'paranoid'};
2144
2454
      # if we are given a username, but can't look it up, maybe name
2145
2455
      # services are down?  let's break out here to allow them to get
2146
2456
      # 'defaults' when we are not running paranoid
2189
2499
 
2190
2500
    # we *still* die if this can't be found
2191
2501
    if (!defined $userdir) {
2192
 
        my $errmsg = "spamd: handle_user unable to find user: '$prefsfrom'\n";
 
2502
        my $errmsg =
 
2503
          "spamd: handle_user (userdir) unable to find user: '$prefsfrom'\n";
2193
2504
        die $errmsg if $spamtest->{'paranoid'};
2194
2505
        # if we are given a username, but can't look it up, maybe name
2195
2506
        # services are down?  let's break out here to allow them to get
2365
2676
    # if we are given a username, but can't look it up, maybe name
2366
2677
    # services are down?  let's break out here to allow them to get
2367
2678
    # 'defaults' when we are not running paranoid
2368
 
    info("spamd: handle_user unable to find user: $username\n");
 
2679
    info("spamd: handle_user (sql) unable to find user: $username");
2369
2680
    return 0;
2370
2681
  }
2371
2682
 
2382
2693
  }
2383
2694
 
2384
2695
  my $spam_conf_dir = $dir . '/.spamassassin'; # needed for Bayes, etc.
 
2696
 
2385
2697
  if ( ($opt{'user-config'} || defined $opt{'home_dir_for_helpers'})
2386
2698
       && ! -d $spam_conf_dir ) {
2387
2699
    if (mkdir $spam_conf_dir, 0700) {
2409
2721
    # if we are given a username, but can't look it up, maybe name
2410
2722
    # services are down?  let's break out here to allow them to get
2411
2723
    # 'defaults' when we are not running paranoid
2412
 
    info("spamd: handle_user unable to find user: $username\n");
 
2724
    info("spamd: handle_user (ldap) unable to find user: $username");
2413
2725
    return 0;
2414
2726
  }
2415
2727
 
2487
2799
sub kill_handler {
2488
2800
  my ($sig) = @_;
2489
2801
  info("spamd: server killed by SIG$sig, shutting down");
2490
 
  $server_inet and $server_inet->close;
2491
 
  $server_unix and $server_unix->close;
2492
 
  $server_ssl  and $server_ssl->close;
 
2802
 
 
2803
  for my $socket_info (@listen_sockets) {
 
2804
    next if !$socket_info;
 
2805
 
 
2806
    my $socket = $socket_info->{socket};
 
2807
    $socket->close  if $socket;  # ignoring status
 
2808
 
 
2809
    my $path = $socket_info->{path};
 
2810
    if (defined $path) {  # unlink a UNIX domain socket
 
2811
      unlink($path) or warn "spamd: cannot unlink $path: $!\n";
 
2812
    }
 
2813
  }
2493
2814
 
2494
2815
  if (defined($opt{'pidfile'})) {
2495
 
    unlink($opt{'pidfile'}) || warn "spamd: cannot unlink $opt{'pidfile'}: $!\n";
2496
 
  }
2497
 
 
2498
 
  # the UNIX domain socket
2499
 
  if (defined($opt{'socketpath'})) {
2500
 
    unlink($opt{'socketpath'}) || warn "spamd: cannot unlink $opt{'socketpath'}: $!\n";
 
2816
    unlink($opt{'pidfile'})
 
2817
      or warn "spamd: cannot unlink $opt{'pidfile'}: $!\n";
2501
2818
  }
2502
2819
 
2503
2820
  $SIG{CHLD} = 'DEFAULT';    # we're going to kill our children
2517
2834
  my ($sig) = @_;
2518
2835
 
2519
2836
  # do NOT call syslog here unless the child's pid is in our list of known
2520
 
  # children.  This is due to syslog-ng brokenness -- bugs 3625, 4237.
 
2837
  # children.  This is due to syslog-ng brokenness -- bugs 3625, 4237;
 
2838
  # see also bug 6745.
2521
2839
 
2522
2840
  # clean up any children which have exited
2523
2841
  for (;;) {
2528
2846
    #
2529
2847
    my $pid = waitpid(-1, WNOHANG);
2530
2848
    last if !$pid || $pid == -1;
2531
 
    my $child_stat = $?;
2532
 
 
2533
 
    if (!defined $children{$pid}) {
2534
 
      # ignore this child; we didn't realise we'd forked it. bug 4237
2535
 
      next;
2536
 
    }
 
2849
    push(@children_exited, [$pid, $?, $sig, time]);
 
2850
  }
 
2851
 
 
2852
  $SIG{CHLD} = \&child_handler;    # reset as necessary, should be at end
 
2853
}
 
2854
 
 
2855
# takes care of dead children, as noted by a child_handler()
 
2856
# called in a main program flow (not from a signal handler)
 
2857
#
 
2858
sub child_cleaner {
 
2859
  while (@children_exited) {
 
2860
    my $tuple = shift(@children_exited);
 
2861
    next if !$tuple;  # just in case
 
2862
    my($pid, $child_stat, $sig, $timestamp) = @$tuple;
 
2863
 
 
2864
    # ignore this child if we didn't realise we'd forked it. bug 4237
 
2865
    next if !defined $children{$pid};
2537
2866
 
2538
2867
    # remove them from our child listing
2539
2868
    delete $children{$pid};
2544
2873
      my $sock = $backchannel->get_socket_for_child($pid);
2545
2874
      if ($sock) { $sock->close(); }
2546
2875
    }
2547
 
 
2548
 
    unless ($Mail::SpamAssassin::Logger::LOG_SA{INHIBIT_LOGGING_IN_SIGCHLD_HANDLER}) {
2549
 
      info("spamd: handled cleanup of child pid [%s]%s: %s",
2550
 
           $pid, (defined $sig ? " due to SIG$sig" : ""),
2551
 
           exit_status_str($child_stat,0));
2552
 
    }
 
2876
    info("spamd: handled cleanup of child pid [%s]%s: %s",
 
2877
         $pid, (defined $sig ? " due to SIG$sig" : ""),
 
2878
         exit_status_str($child_stat,0));
2553
2879
  }
2554
 
 
2555
 
  $SIG{CHLD} = \&child_handler;    # reset as necessary, should be at end
2556
2880
}
2557
2881
 
2558
2882
sub restart_handler {
2576
2900
  }
2577
2901
  %children = ();
2578
2902
 
2579
 
  unless ( !$server_inet || $server_inet->eof ) {
2580
 
    $server_inet->shutdown(2);
2581
 
    $server_inet->close;
2582
 
    info("spamd: server INET socket closed");
2583
 
  }
2584
 
 
2585
 
  unless ( !$server_unix || $server_unix->eof ) {
2586
 
    $server_unix->shutdown(2);
2587
 
    $server_unix->close;
2588
 
    if (defined($opt{'socketpath'})) {
2589
 
      unlink($opt{'socketpath'}) || warn "spamd: cannot unlink $opt{'socketpath'}: $!\n";
 
2903
  for my $socket_info (@listen_sockets) {
 
2904
    next if !$socket_info;
 
2905
    my $socket = $socket_info->{socket};
 
2906
    next if !$socket;
 
2907
    my $socket_specs = $socket_info->{specs};
 
2908
    $socket->shutdown(2) if !$socket->eof;
 
2909
    $socket->close;
 
2910
    if ($socket->isa('IO::Socket::UNIX') && defined $socket_specs) {
 
2911
      unlink($socket_specs)
 
2912
        or warn "spamd: cannot unlink $socket_specs: $!\n";
2590
2913
    }
2591
 
    info("spamd: server UNIX socket closed");
 
2914
    info("spamd: server socket closed, type %s", ref $socket);
2592
2915
  }
2593
2916
 
2594
 
  unless ( !$server_ssl || $server_ssl->eof ) {
2595
 
    $server_ssl->shutdown(2);
2596
 
    $server_ssl->close;
2597
 
    info("spamd: server SSL socket closed");
2598
 
  }
2599
2917
  $got_sighup = 1;
2600
2918
}
2601
2919
 
2657
2975
 
2658
2976
sub set_allowed_ip {
2659
2977
  foreach (@_) {
2660
 
    $allowed_nets->add_cidr($_) or die "spamd: aborting due to add_cidr error\n";
 
2978
    my $ip = $_;
 
2979
    local($1,$2);
 
2980
    # strip optional square brackets
 
2981
    $ip =~ s{^ \[ (.*) \] \z}{$1}xs
 
2982
    || $ip =~ s{^ \[ (.*) \] ( / \d+ ) \z}{$1$2}xs;
 
2983
  # dbg("spamd: set_allowed_ip %s", $ip);
 
2984
    $allowed_nets->add_cidr($ip)
 
2985
      or die "spamd: aborting due to add_cidr error\n";
2661
2986
  }
2662
2987
}
2663
2988
 
2679
3004
  delete $ENV{'TMPDIR'} if ( !defined $ENV{'TMPDIR'} );
2680
3005
 
2681
3006
  my $tmphome = File::Spec->catdir( $tmpdir, "spamd-$$-init" );
2682
 
  $tmphome = Mail::SpamAssassin::Util::untaint_file_path($tmphome);
 
3007
  $tmphome = untaint_file_path($tmphome);
2683
3008
 
2684
3009
  my $tmpsadir = File::Spec->catdir( $tmphome, ".spamassassin" );
2685
3010
 
2710
3035
    opendir( TMPDIR, $d ) or $err ||= "open $d: $!";
2711
3036
    unless ($err) {
2712
3037
      foreach my $f ( File::Spec->no_upwards( readdir(TMPDIR) ) ) {
2713
 
        $f =
2714
 
          Mail::SpamAssassin::Util::untaint_file_path(
2715
 
          File::Spec->catfile( $d, $f ) );
 
3038
        $f = untaint_file_path( File::Spec->catfile( $d, $f ) );
2716
3039
        unlink($f) or $err ||= "remove $f: $!";
2717
3040
      }
2718
3041
      closedir(TMPDIR) or $err ||= "close $d: $!";
2744
3067
                  || (exists &Errno::EWOULDBLOCK && $! == &Errno::EWOULDBLOCK))
2745
3068
          {
2746
3069
              # an error that wasn't non-blocking I/O-related.  that's serious
2747
 
              return undef;
 
3070
              return;
2748
3071
          }
2749
3072
          # errcode says to try again
2750
3073
      }
2763
3086
}
2764
3087
 
2765
3088
sub map_server_sockets {
2766
 
  $fd_inet = $server_inet ? $server_inet->fileno : undef;
2767
 
  $fd_unix = $server_unix ? $server_unix->fileno : undef;
2768
 
  $fd_ssl  = $server_ssl  ? $server_ssl->fileno  : undef;
2769
3089
 
2770
3090
  $server_select_mask = '';
2771
 
  $server_inet and vec($server_select_mask, $fd_inet, 1) = 1;
2772
 
  $server_unix and vec($server_select_mask, $fd_unix, 1) = 1;
2773
 
  $server_ssl  and vec($server_select_mask, $fd_ssl,  1) = 1;
 
3091
  for my $socket_info (@listen_sockets) {
 
3092
    next if !$socket_info;
 
3093
    my $fd = $socket_info->{fd};
 
3094
    vec($server_select_mask, $fd, 1) = 1  if defined $fd;
 
3095
  }
 
3096
  dbg("spamd: server listen sockets fd bit field: %s",
 
3097
      unpack('b*', $server_select_mask));
2774
3098
 
2775
3099
  my $back_selector = $server_select_mask;
2776
3100
  $backchannel->set_selector(\$back_selector);
2777
 
 
2778
 
  # and set a boolean indicating whether or not we have > 1 server socket
2779
 
  $have_multiple_server_socks =
2780
 
      ((defined $fd_inet ? 1 : 0) +
2781
 
      (defined $fd_unix ? 1 : 0) +
2782
 
      (defined $fd_ssl  ? 1 : 0)) > 1;
2783
3101
}
2784
3102
 
2785
3103
# do this in advance, since we want to minimize work when SIGHUP
2846
3164
 --cf='config line'                Additional line of configuration
2847
3165
 -d, --daemonize                   Daemonize
2848
3166
 -h, --help                        Print usage message
2849
 
 -i [ipaddr], --listen-ip=ipaddr   Listen on the IP ipaddr
2850
 
 --ipv4only, --ipv4-only, --ipv4   Disable attempted use of ipv6 for DNS
2851
 
 -p port, --port=port              Listen on specified port
 
3167
 -i [ip_or_name[:port]], --listen=[ip_or_name[:port]] Listen on IP addr and port
 
3168
 -p port, --port=port              Listen on specified port, may be overridden by -i
 
3169
 -4, --ipv4-only, --ipv4           Use IPv4 where applicable, disables IPv6
 
3170
 -6                                Use IPv6 where applicable, disables IPv4
 
3171
 -A host,..., --allowed-ips=..,..  Restrict to IP addresses which can connect
2852
3172
 -m num, --max-children=num        Allow maximum num children
2853
3173
 --min-children=num                Allow minimum num children
2854
 
 --min-spare=num                Lower limit for number of spare children
2855
 
 --max-spare=num                Upper limit for number of spare children
 
3174
 --min-spare=num                   Lower limit for number of spare children
 
3175
 --max-spare=num                   Upper limit for number of spare children
2856
3176
 --max-conn-per-child=num          Maximum connections accepted by child 
2857
3177
                                   before it is respawned
2858
3178
 --round-robin                     Use traditional prefork algorithm
2875
3195
 -g groupname, --groupname=groupname  Run as groupname
2876
3196
 -v, --vpopmail                    Enable vpopmail config
2877
3197
 -x, --nouser-config               Disable user config files
2878
 
 --auth-ident                      Use ident to authenticate spamc user
 
3198
 --auth-ident                      Use ident to identify spamc user (deprecated)
2879
3199
 --ident-timeout=timeout           Timeout for ident connections
2880
 
 -A host,..., --allowed-ips=..,..  Limit ip addresses which can connect
2881
3200
 -D, --debug[=areas]               Print debugging messages (for areas)
2882
3201
 -L, --local                       Use local tests only (no DNS)
2883
3202
 -P, --paranoid                    Die upon user errors
2884
 
 -H [dir], --helper-home-dir[=dir]  Specify a different HOME directory
2885
 
 --ssl                             Run an SSL server
2886
 
 --ssl-port port                   Listen on port for SSL connections
 
3203
 -H [dir], --helper-home-dir[=dir] Specify a different HOME directory
 
3204
 --ssl                             Enable SSL on TCP connections
 
3205
 --ssl-port port                   Override --port setting for SSL connections
2887
3206
 --ssl-version sslversion          Specify SSL protocol version to use
2888
3207
 --server-key keyfile              Specify an SSL keyfile
2889
3208
 --server-cert certfile            Specify an SSL certificate
2890
 
 --socketpath=path                 Listen on given UNIX domain socket
 
3209
 --socketpath=path                 Listen on a given UNIX domain socket
2891
3210
 --socketowner=name                Set UNIX domain socket file's owner
2892
3211
 --socketgroup=name                Set UNIX domain socket file's group
2893
3212
 --socketmode=mode                 Set UNIX domain socket file's mode
2894
3213
 -V, --version                     Print version and exit
2895
3214
 
 
3215
The --listen option (or -i) may be specified multiple times, its syntax
 
3216
is: [ ssl: ] [ host-name-or-IP-address ] [ : port ]  or an absolute path
 
3217
(filename) of a Unix socket.  If port is omitted it defaults to --port or
 
3218
to 783.  Option --ssl implies a prefix 'ssl:'.  An IPv6 address should be
 
3219
enclosed in square brackets, e.g. [::1]:783, an IPv4 address may be but
 
3220
need not be enclosed in square brackets.  An asterisk '*' in place of a
 
3221
hostname implies an unspecified address, ('0.0.0.0' or '::'), i.e. it
 
3222
binds to all interfaces. An empty option value implies '*'. A default
 
3223
is '--listen localhost', which binds to a loopback interface only.
 
3224
 
 
3225
 
2896
3226
=head1 DESCRIPTION
2897
3227
 
2898
3228
The purpose of this program is to provide a daemonized version of the
2971
3301
 
2972
3302
Print version information, then exit without further action.
2973
3303
 
2974
 
=item B<-i> [I<ipaddress>], B<--listen-ip>[=I<ipaddress>], B<--ip-address>[=I<ipaddress>]
 
3304
=item B<-i> [I<ipaddress>[:<port>]], B<--listen>[=I<ipaddress>[:<port>]]
2975
3305
 
2976
 
Tells spamd to listen on the specified IP address (defaults to 127.0.0.1).  If
2977
 
you specify no IP address after the switch, spamd will listen on all interfaces.
2978
 
(This is equal to the address 0.0.0.0).  You can also use a valid hostname which
2979
 
will make spamd listen on the first address that name resolves to.
 
3306
Additional alias names for this option are --listen-ip and --ip-address.
 
3307
Tells spamd to listen on the specified IP address, defaults to a loopback
 
3308
interface, i.e. C<--listen localhost>).  If no value is specified after the
 
3309
switch, or if an asterisk '*' stands in place of an <ipaddress>, spamd will
 
3310
listen on all interfaces - this is equivalent to address '0.0.0.0' for IPv4
 
3311
and to '::' for IPv6. You can also use a valid hostname which will make spamd
 
3312
listen on all addresses that a name resolves to. The option may be specified
 
3313
multiple times. See also options -4 and -6 for restricting address family
 
3314
to IPv4 or to IPv6. If a port is specified it overrides for this socket the
 
3315
global --port (and --ssl-port) setting. An IPv6 addresses should be enclosed
 
3316
in square brackets, e.g. [::1]:783. For compatibility square brackets on an
 
3317
IPv6 address may be omitted if a port number specification is also omitted.
2980
3318
 
2981
3319
=item B<-p> I<port>, B<--port>=I<port>
2982
3320
 
3186
3524
immediately if authentication fails.  In this case, spamc will pass
3187
3525
the mail through unchecked.  Failure to connect to an ident server,
3188
3526
and response timeouts are considered authentication failures.  This
3189
 
requires that Net::Ident be installed.
 
3527
requires that Net::Ident be installed. Deprecated.
3190
3528
 
3191
3529
=item B<--ident-timeout>=I<timeout>
3192
3530
 
3193
3531
Wait at most I<timeout> seconds for a response to ident queries.
3194
 
Authentication that takes long that I<timeout> seconds will fail, and
 
3532
Ident query that takes longer that I<timeout> seconds will fail, and
3195
3533
mail will not be processed.  Setting this to 0.0 or less results in no
3196
3534
timeout, which is STRONGLY discouraged.  The default is 5 seconds.
3197
3535
 
3198
3536
=item B<-A> I<host,...>, B<--allowed-ips>=I<host,...>
3199
3537
 
3200
 
Specify a list of authorized hosts or networks which can connect to this spamd
3201
 
instance. Single IP addresses can be given, ranges of IP addresses in
3202
 
address/masklength CIDR format, or ranges of IP addresses by listing 3 or less
3203
 
octets with a trailing dot.  Hostnames are not supported, only IP addresses.
 
3538
Specify a comma-separated list of authorized hosts or networks which
 
3539
can connect to this spamd instance. Each element of the list is either a
 
3540
single IP addresses, or a range of IP addresses in address/masklength CIDR
 
3541
notation, or ranges of IPv4 addresses by specifying 3 or less octets with
 
3542
a trailing dot.  Hostnames are not supported, only IPv4 or IPv6 addresses.
3204
3543
This option can be specified multiple times, or can take a list of addresses
3205
 
separated by commas.  Examples:
 
3544
separated by commas.  IPv6 addresses may be (but need not be) enclosed
 
3545
in square brackets for consistency with option B<--listen>.  Examples:
3206
3546
 
3207
3547
B<-A 10.11.12.13> -- only allow connections from C<10.11.12.13>.
3208
3548
 
3214
3554
 
3215
3555
B<-A 10.> -- allow connections from any machine in the range C<10.*.*.*>.
3216
3556
 
3217
 
By default, connections are only accepted from localhost [127.0.0.1].
 
3557
B<-A [2001:db8::]/32,192.0.2.0/24,::1,127.0.0.0/8> -- only accept
 
3558
connections from specified test networks and from localhost.
 
3559
 
 
3560
In absence of the B<-A> option, connections are only accepted from
 
3561
IP address 127.0.0.1 or ::1, i.e. from localhost on a loopback interface.
3218
3562
 
3219
3563
=item B<-D> [I<area,...>], B<--debug> [I<area,...>]
3220
3564
 
3233
3577
 
3234
3578
        C<http://wiki.apache.org/spamassassin/DebugChannels>
3235
3579
 
3236
 
=item B< --ipv4only>, B<--ipv4-only>, B<--ipv4>
3237
 
 
3238
 
Do not use IPv6 for DNS tests. Use if the existing tests
3239
 
for IPv6 availability produce incorrect results or crashes.
 
3580
=item B<-4>, B<--ipv4only>, B<--ipv4-only>, B<--ipv4>
 
3581
 
 
3582
Use IPv4 where applicable, do not use IPv6.
 
3583
The option affects a set of listen sockets (see option C<--listen>)
 
3584
and disables IPv6 for DNS tests.
 
3585
 
 
3586
=item B<-6>
 
3587
 
 
3588
Use IPv6 where applicable, do not use IPv4.
 
3589
The option affects a set of listen sockets (see option C<--listen>)
 
3590
and disables IPv4 for DNS tests. Installing a module IO::Socket::IP
 
3591
is recommended if spamd is expected to receive requests over IPv6.
3240
3592
 
3241
3593
=item B<-L>, B<--local>
3242
3594
 
3341
3693
 
3342
3694
=item B<--ssl-version>=I<sslversion>
3343
3695
 
3344
 
Specify the SSL protocol version to use, one of
3345
 
B<sslv2>, B<sslv3>, B<tlsv1>, or B<sslv23>.
3346
 
The default, B<sslv23>, is the most flexible, accepting a SSLv2 or higher
3347
 
hello handshake, then negotiating use of SSLv3 or TLSv1 protocol if the client
3348
 
can accept it.
3349
 
Specifying B<--ssl-version> implies B<--ssl>.
 
3696
Specify the SSL protocol version to use, one of B<sslv3> or B<tlsv1>.
 
3697
The default, B<sslv3>, is the most flexible, accepting a SSLv3 or
 
3698
higher hello handshake, then negotiating use of SSLv3 or TLSv1
 
3699
protocol if the client can accept it.  Specifying B<--ssl-version>
 
3700
implies B<--ssl>.
3350
3701
 
3351
3702
=item B<--server-key> I<keyfile>
3352
3703
 
3358
3709
 
3359
3710
=item B<--socketpath> I<pathname>
3360
3711
 
3361
 
Listen on UNIX domain path I<pathname> instead of a TCP socket.
 
3712
Listen on a UNIX domain socket at path I<pathname>, in addition to
 
3713
sockets specified with a C<--listen> option. This option is provided
 
3714
for compatibility with older versions of spamd. Starting with version
 
3715
3.4.0 the C<--listen> option can also take a UNIX domain socket as its
 
3716
value (an absolute path name). Unlike C<--socketpath>, the C<--listen>
 
3717
option may be specified multiple times if spamd needs to listen on
 
3718
multiple UNIX or INET or INET6 sockets.
3362
3719
 
3363
3720
Warning: the Perl support on BSD platforms for UNIX domain sockets seems to
3364
 
have a bug regarding paths of over 100 bytes or so (SpamAssassin bug 4380).  If
3365
 
you see a 'could not find newly-created UNIX socket' error message, and the
3366
 
path appears truncated, this may be the cause.  Try using a shorter path
 
3721
have a bug regarding paths of over 100 bytes or so (SpamAssassin bug 4380).
 
3722
If you see a 'could not find newly-created UNIX socket' error message, and
 
3723
the path appears truncated, this may be the cause.  Try using a shorter path
3367
3724
to the socket.
3368
3725
 
3369
 
By default, use of B<--socketpath> will inhibit SSL connections and unencrypted
3370
 
TCP connections.  To enable them, specify B<--port> and/or B<--ssl-port>
3371
 
explicitly.
 
3726
By default, use of B<--socketpath> without B<--listen> will inhibit
 
3727
SSL connections and unencrypted TCP connections.  To add other sockets,
 
3728
specify them with B<--listen>, e.g. '--listen=:' or '--listen=*:'
3372
3729
 
3373
3730
=item B<--socketowner> I<name>
3374
3731