View | Details | Raw Unified | Return to bug 1028
Collapse All | Expand All

(-)spamd.raw (-30 / +84 lines)
Lines 12-18 Link Here
12
12
13
use lib '../lib';	# added by jm for use inside the distro
13
use lib '../lib';	# added by jm for use inside the distro
14
use strict;
14
use strict;
15
use Socket;
15
use IO::Socket;
16
use IO::Handle;
16
use Carp;
17
use Carp;
17
use Config;
18
use Config;
18
use Mail::SpamAssassin;
19
use Mail::SpamAssassin;
Lines 48-53 Link Here
48
my @OLD_ARGV = @ARGV;    # Getopt::Long tends to clear @ARGV
50
my @OLD_ARGV = @ARGV;    # Getopt::Long tends to clear @ARGV
49
Getopt::Long::Configure ("bundling");
51
Getopt::Long::Configure ("bundling");
50
GetOptions(
52
GetOptions(
53
	'server-key=s' => \$opt{'server-key'},
54
	'server-cert=s' => \$opt{'server-cert'},
55
	'ssl' => \$opt{'ssl'},
51
	'auto-whitelist|whitelist|a' => \$opt{'auto-whitelist'},
56
	'auto-whitelist|whitelist|a' => \$opt{'auto-whitelist'},
52
	'create-prefs!', => \$opt{'create-prefs'}, 'c' => \$opt{'create-prefs'},
57
	'create-prefs!', => \$opt{'create-prefs'}, 'c' => \$opt{'create-prefs'},
53
	'daemonize!' => \$opt{'daemonize'}, 'd' => \$opt{'daemonize'},
58
	'daemonize!' => \$opt{'daemonize'}, 'd' => \$opt{'daemonize'},
Lines 79-84 Link Here
79
84
80
$opt{'help'} and pod2usage(-exitval => $resphash{'EX_USAGE'}, -verbose => 0, -message => 'For more details, use "man spamd"');
85
$opt{'help'} and pod2usage(-exitval => $resphash{'EX_USAGE'}, -verbose => 0, -message => 'For more details, use "man spamd"');
81
86
87
# Check for server certs
88
$opt{'server-key'} ||= "$LOCAL_RULES_DIR/certs/server-key.pem";
89
$opt{'server-cert'} ||= "$LOCAL_RULES_DIR/certs/server-cert.pem";
90
if ($opt{'ssl'})
91
{
92
    require IO::Socket::SSL;
93
94
    if (!-e $opt{'server-key'})
95
    {
96
	die "The server key file $opt{'server-key'} does not exist";
97
    }
98
    if (!-e $opt{'server-cert'})
99
    {
100
	die "The server certificate file $opt{'server-cert'} does not exist";
101
    }
102
}
103
82
# These can be changed on command line with -A flag
104
# These can be changed on command line with -A flag
83
if(@{$opt{'allowed-ip'}})
105
if(@{$opt{'allowed-ip'}})
84
{
106
{
Lines 138-153 Link Here
138
setlogsock($socktype) unless $log_facility eq 'stderr';
161
setlogsock($socktype) unless $log_facility eq 'stderr';
139
162
140
my $port = $opt{'port'} || 783;
163
my $port = $opt{'port'} || 783;
141
my $addr = gethostbyname($opt{'listen-ip'} || '127.0.0.1');
164
my $addr = (gethostbyname($opt{'listen-ip'} || '127.0.0.1'))[0];
142
my $proto = getprotobyname('tcp');
165
my $proto = getprotobyname('tcp');
143
166
144
($port) = $port =~ /^(\d+)$/ or die "invalid port";
167
($port) = $port =~ /^(\d+)$/ or die "invalid port";
145
168
146
# Be a well-behaved daemon
169
# Be a well-behaved daemon
147
socket(Server, PF_INET, SOCK_STREAM, $proto)            || die "socket: $!";
170
my $server;
148
setsockopt(Server,SOL_SOCKET,SO_REUSEADDR,pack("l",1))  || die "setsockopt: $!";
171
if ($opt{'ssl'})
149
bind(Server, sockaddr_in($port, $addr))                 || die "bind: $!";
172
{
150
listen(Server,SOMAXCONN)                                || die "listen: $!";
173
    $server = new IO::Socket::SSL(LocalAddr => $addr,
174
				  LocalPort => $port,
175
				  Proto => $proto,
176
				  Type => SOCK_STREAM,
177
				  ReuseAddr => 1,
178
				  Listen => 5,
179
				  SSL_verify_mode => 0x00,
180
				  SSL_key_file => $opt{'server-key'},
181
				  SSL_cert_file => $opt{'server-cert'})
182
	|| die "new IO::Socket::SSL: $! $@";
183
}
184
else
185
{
186
    $server = new IO::Socket::INET(LocalAddr => $addr,
187
				   LocalPort => $port,
188
				   Proto => $proto,
189
				   Type => SOCK_STREAM,
190
				   ReuseAddr => 1,
191
				   Listen => 10)
192
	|| die "new IO::Socket::INET: $! $@";
193
}
151
194
152
$opt{'daemonize'} and daemonize();
195
$opt{'daemonize'} and daemonize();
153
196
Lines 205-210 Link Here
205
248
206
my $current_user;
249
my $current_user;
207
my $paddr;
250
my $paddr;
251
my $client;
208
252
209
sub REAPER { # Adapted from the perlipc manpage
253
sub REAPER { # Adapted from the perlipc manpage
210
	cleanupchildren;
254
	cleanupchildren;
Lines 227-238 Link Here
227
}
271
}
228
logmsg "server started on port $port (running version ".Mail::SpamAssassin::Version().")";
272
logmsg "server started on port $port (running version ".Mail::SpamAssassin::Version().")";
229
273
230
for ( ; ($paddr = accept(Client,Server)) ; close Client)
274
while (1)
231
{
275
{
232
276
    $client = $server->accept
277
	|| next;
233
    my $start = time;
278
    my $start = time;
234
279
235
    my($port,$iaddr) = sockaddr_in($paddr);
280
    my($port,$iaddr) = sockaddr_in($client->peername);
236
    my $name = gethostbyaddr($iaddr,AF_INET);
281
    my $name = gethostbyaddr($iaddr,AF_INET);
237
282
238
    if (ip_is_allowed(inet_ntoa($iaddr))) {
283
    if (ip_is_allowed(inet_ntoa($iaddr))) {
Lines 241-257 Link Here
241
    } else {
286
    } else {
242
	logmsg "unauthorized connection from $name [",
287
	logmsg "unauthorized connection from $name [",
243
	inet_ntoa($iaddr),"] at port $port";
288
	inet_ntoa($iaddr),"] at port $port";
289
	$client->close;
244
	next;
290
	next;
245
    }
291
    }
246
292
247
    spawn sub {
293
    spawn sub {
248
	$|=1; # always immediately flush output
294
	$|=1; # always immediately flush output
249
295
296
	my ($client) = @_;
297
250
	# First request line off stream
298
	# First request line off stream
251
        local $_ = <STDIN>;
299
        local $_ = <$client>;
252
300
253
	if (!defined $_) {
301
	if (!defined $_) {
254
	    protocol_error ("(closed before headers)");
302
	    protocol_error ("(closed before headers)", $client);
255
	    return 1;
303
	    return 1;
256
	}
304
	}
257
305
Lines 285-294 Link Here
285
	    {
333
	    {
286
		while(1)
334
		while(1)
287
                {
335
                {
288
                    $_ = <STDIN>;
336
                    $_ = <$client>;
289
                    if(!defined $_)
337
                    if(!defined $_)
290
                    {
338
                    {
291
                        protocol_error ("(EOF during headers)");
339
                        protocol_error ("(EOF during headers)", $client);
292
                        return 1;
340
                        return 1;
293
                    }
341
                    }
294
342
Lines 348-354 Link Here
348
            my $actual_length;
396
            my $actual_length;
349
            my $in_header = 1;
397
            my $in_header = 1;
350
            my $msgid;
398
            my $msgid;
351
            for (<STDIN>) {
399
            while (<$client>) {
352
                if ($in_header) {
400
                if ($in_header) {
353
                    if (/^$/) {
401
                    if (/^$/) {
354
                        $in_header = 0;
402
                        $in_header = 0;
Lines 363-368 Link Here
363
                }
411
                }
364
                push(@msglines, $_);
412
                push(@msglines, $_);
365
                $actual_length += length;
413
                $actual_length += length;
414
		last if $actual_length == $expected_length;
366
            }
415
            }
367
416
368
            logmsg "checking message $msgid for $current_user:$>" .
417
            logmsg "checking message $msgid for $current_user:$>" .
Lines 403-411 Link Here
403
            {
452
            {
404
                $response_header .= "Spam: False ; $msg_score / $msg_threshold";
453
                $response_header .= "Spam: False ; $msg_score / $msg_threshold";
405
	    }
454
	    }
406
            print $response_header, "\r\n\r\n";
455
            print $client $response_header, "\r\n\r\n";
407
	    print $status->get_names_of_tests_hit,"\r\n" if ($method eq "SYMBOLS");
456
	    print $client $status->get_names_of_tests_hit,"\r\n" if ($method eq "SYMBOLS");
408
	    print $status->get_report,"\r\n" if ($method eq "REPORT" or $method eq "REPORT_IFSPAM" and $status->is_spam);
457
	    print $client $status->get_report,"\r\n" if ($method eq "REPORT" or $method eq "REPORT_IFSPAM" and $status->is_spam);
409
	    $current_user ||= '(unknown)';
458
	    $current_user ||= '(unknown)';
410
	    logmsg "$was_it_spam ($msg_score/$msg_threshold) for $current_user:$> in ".
459
	    logmsg "$was_it_spam ($msg_score/$msg_threshold) for $current_user:$> in ".
411
		sprintf("%3d", time - $start) ." seconds, $actual_length bytes.\n";
460
		sprintf("%3d", time - $start) ." seconds, $actual_length bytes.\n";
Lines 429-438 Link Here
429
	    {
478
	    {
430
		while(1)
479
		while(1)
431
                {
480
                {
432
                    $_ = <STDIN>;
481
                    $_ = <$client>;
433
                    if(!defined $_)
482
                    if(!defined $_)
434
                    {
483
                    {
435
                        protocol_error ("(EOF during headers)");
484
                        protocol_error ("(EOF during headers)", $client);
436
                        return 1;
485
                        return 1;
437
                    }
486
                    }
438
487
Lines 492-498 Link Here
492
            my $actual_length;
541
            my $actual_length;
493
            my $in_header = 1;
542
            my $in_header = 1;
494
            my $msgid;
543
            my $msgid;
495
            for (<STDIN>) {
544
            while (<$client>) {
496
                if ($in_header) {
545
                if ($in_header) {
497
                    if (/^$/) {
546
                    if (/^$/) {
498
                        $in_header = 0;
547
                        $in_header = 0;
Lines 507-512 Link Here
507
                }
556
                }
508
                push(@msglines, $_);
557
                push(@msglines, $_);
509
                $actual_length += length;
558
                $actual_length += length;
559
		last if $actual_length == $expected_length;
510
            }
560
            }
511
561
512
            logmsg "processing message $msgid for $current_user:$>" .
562
            logmsg "processing message $msgid for $current_user:$>" .
Lines 519-525 Link Here
519
	    # Check length if we're supposed to
569
	    # Check length if we're supposed to
520
	    if($expected_length)
570
	    if($expected_length)
521
	    {
571
	    {
522
		if($actual_length != $expected_length) { protocol_error ("(Content-length mismatch: $expected_length vs. $actual_length)"); return 1; }
572
		if($actual_length != $expected_length) {
573
	    protocol_error ("(Content-length mismatch: $expected_length vs. $actual_length)", $client); return 1; }
523
	    }
574
	    }
524
575
525
	    # Now use copy-on-writed (hopefully) SA object
576
	    # Now use copy-on-writed (hopefully) SA object
Lines 531-543 Link Here
531
	    my $msg_resp_length = length($msg_resp);
582
	    my $msg_resp_length = length($msg_resp);
532
	    if($version >= 1.2) # Spamc protocol 1.2 means it accepts content-length
583
	    if($version >= 1.2) # Spamc protocol 1.2 means it accepts content-length
533
	    {
584
	    {
534
		print "SPAMD/1.1 $resphash{$resp} $resp\r\n",
585
		print $client "SPAMD/1.1 $resphash{$resp} $resp\r\n",
535
		"Content-length: $msg_resp_length\r\n\r\n",
586
		"Content-length: $msg_resp_length\r\n\r\n",
536
		$msg_resp;
587
		$msg_resp;
537
	    }
588
	    }
538
	    else # Earlier than 1.2 didn't accept content-length
589
	    else # Earlier than 1.2 didn't accept content-length
539
	    {
590
	    {
540
		print "SPAMD/1.0 $resphash{$resp} $resp\r\n",
591
		print $client "SPAMD/1.0 $resphash{$resp} $resp\r\n",
541
		$msg_resp;
592
		$msg_resp;
542
	    }
593
	    }
543
	    my $was_it_spam;
594
	    my $was_it_spam;
Lines 555-561 Link Here
555
606
556
	else
607
	else
557
	{
608
	{
558
	    protocol_error ($_);
609
	    protocol_error ($_, $client);
559
	}
610
	}
560
    };
611
    };
561
612
Lines 566-578 Link Here
566
    # essentially does this!
617
    # essentially does this!
567
618
568
    cleanupchildren;
619
    cleanupchildren;
620
    $client->close;
569
}
621
}
570
622
571
sub protocol_error {
623
sub protocol_error {
572
    local $_ = shift;
624
    local $_ = shift;
625
    my $client = shift;
573
626
574
    my $resp = "EX_PROTOCOL";
627
    my $resp = "EX_PROTOCOL";
575
    print "SPAMD/1.0 $resphash{$resp} Bad header line: $_\r\n";
628
    print $client "SPAMD/1.0 $resphash{$resp} Bad header line: $_\r\n";
576
    logmsg "bad protocol: header error: $_";
629
    logmsg "bad protocol: header error: $_";
577
}
630
}
578
631
Lines 605-614 Link Here
605
    }
658
    }
606
    # else I'm the child -- go spawn
659
    # else I'm the child -- go spawn
607
660
608
    close Server;
661
    $server->close;
609
    open(STDIN,  "<&Client")   || die "can't dup client to stdin";
662
    #STDIN->fdopen($client, "r") || die "can't dup client to stdin";
610
    open(STDOUT, ">&Client")   || die "can't dup client to stdout";
663
    #STDOUT->fdopen($client, "w")|| die "can't dup client to stdout";
611
    exit &$coderef();
664
    exit &$coderef($client);
612
}
665
}
613
666
614
sub handle_user
667
sub handle_user
Lines 773-779 Link Here
773
{
826
{
774
    my ($sig) = @_;
827
    my ($sig) = @_;
775
    logmsg "server killed by SIG$sig, shutting down";
828
    logmsg "server killed by SIG$sig, shutting down";
776
    close Server;
829
    $server->close;
777
    defined($opt{'pidfile'}) and unlink($opt{'pidfile'});
830
    defined($opt{'pidfile'}) and unlink($opt{'pidfile'});
778
    exit 0;
831
    exit 0;
779
}
832
}
Lines 855-860 Link Here
855
 -V, --virtual-config=dir           Enable Virtual configs (needs -x)
908
 -V, --virtual-config=dir           Enable Virtual configs (needs -x)
856
 -r pidfile, --pidfile              Write the process id to pidfile
909
 -r pidfile, --pidfile              Write the process id to pidfile
857
 -s facility, --syslog=facility     Specify the syslog facility (default: mail)
910
 -s facility, --syslog=facility     Specify the syslog facility (default: mail)
911
 --server-key keyfile               Specify an SSL keyfile
912
 --server-cert certfile             Specify an SSL certificate
913
 --ssl                              Run an SSL server
858
 -u username, --username=username   Run as username
914
 -u username, --username=username   Run as username
859
 -v, --vpopmail                     Enable vpopmail config
915
 -v, --vpopmail                     Enable vpopmail config
860
 -x, --nouser-config                Disable user config files
916
 -x, --nouser-config                Disable user config files

Return to bug 1028