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

(-)t/root_spamd_tell_x.t (+58 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
use lib '.'; use lib 't';
4
use SATest; sa_t_init("root_spamd_tell_x");
5
use Test;
6
7
use constant TEST_ENABLED => conf_bool('run_root_tests');
8
use constant IS_ROOT => eval { ($> == 0); };
9
use constant RUN_TESTS => (TEST_ENABLED && IS_ROOT);
10
11
BEGIN { plan tests => (RUN_TESTS ? 6 : 0) };
12
exit unless RUN_TESTS;
13
14
# ---------------------------------------------------------------------------
15
16
%patterns = (
17
q{ Message successfully } => 'learned',
18
);
19
20
# run spamc as unpriv uid
21
$spamc = "sudo -u nobody $spamc";
22
23
# remove these first
24
unlink('log/user_state/bayes_seen');
25
unlink('log/user_state/bayes_toks');
26
27
# ensure it is writable by all
28
use File::Path; mkpath("log/user_state"); chmod 01777, "log/user_state";
29
30
ok(start_spamd("-L --allow-tell --create-prefs -x"));
31
32
ok(spamcrun("-lx -L ham < data/spam/001", \&patterns_run_cb));
33
ok_all_patterns();
34
35
ok(stop_spamd());
36
37
# ensure these are not owned by root
38
ok check_owner('log/user_state/bayes_seen');
39
ok check_owner('log/user_state/bayes_toks');
40
41
sub check_owner {
42
  my $f = shift;
43
  my @stat = stat $f;
44
45
  print "stat($f) = ".join(', ', @stat)."\n";
46
47
  if (!defined $stat[1]) {
48
    warn "no stat for $f";
49
    return 0;
50
  }
51
  elsif ($stat[4] == 0) {
52
    warn "stat for $f: owner is root";
53
    return 0;
54
  }
55
  else {
56
    return 1;
57
  }
58
}
(-)t/root_spamd_tell.t (+58 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
use lib '.'; use lib 't';
4
use SATest; sa_t_init("root_spamd_tell");
5
use Test;
6
7
use constant TEST_ENABLED => conf_bool('run_root_tests');
8
use constant IS_ROOT => eval { ($> == 0); };
9
use constant RUN_TESTS => (TEST_ENABLED && IS_ROOT);
10
11
BEGIN { plan tests => (RUN_TESTS ? 6 : 0) };
12
exit unless RUN_TESTS;
13
14
# ---------------------------------------------------------------------------
15
16
%patterns = (
17
q{ Message successfully } => 'learned',
18
);
19
20
# run spamc as unpriv uid
21
$spamc = "sudo -u nobody $spamc";
22
23
# remove these first
24
unlink('log/user_state/bayes_seen');
25
unlink('log/user_state/bayes_toks');
26
27
# ensure it is writable by all
28
use File::Path; mkpath("log/user_state"); chmod 01777, "log/user_state";
29
30
ok(start_spamd("-L --allow-tell"));
31
32
ok(spamcrun("-lx -L ham < data/spam/001", \&patterns_run_cb));
33
ok_all_patterns();
34
35
ok(stop_spamd());
36
37
# ensure these are not owned by root
38
ok check_owner('log/user_state/bayes_seen');
39
ok check_owner('log/user_state/bayes_toks');
40
41
sub check_owner {
42
  my $f = shift;
43
  my @stat = stat $f;
44
45
  print "stat($f) = ".join(', ', @stat)."\n";
46
47
  if (!defined $stat[1]) {
48
    warn "no stat for $f";
49
    return 0;
50
  }
51
  elsif ($stat[4] == 0) {
52
    warn "stat for $f: owner is root";
53
    return 0;
54
  }
55
  else {
56
    return 1;
57
  }
58
}
(-)t/root_spamd_tell_paranoid.t (+58 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
use lib '.'; use lib 't';
4
use SATest; sa_t_init("root_spamd_tell_paranoid");
5
use Test;
6
7
use constant TEST_ENABLED => conf_bool('run_root_tests');
8
use constant IS_ROOT => eval { ($> == 0); };
9
use constant RUN_TESTS => (TEST_ENABLED && IS_ROOT);
10
11
BEGIN { plan tests => (RUN_TESTS ? 6 : 0) };
12
exit unless RUN_TESTS;
13
14
# ---------------------------------------------------------------------------
15
16
%patterns = (
17
q{ Message successfully } => 'learned',
18
);
19
20
# run spamc as unpriv uid
21
$spamc = "sudo -u nobody $spamc";
22
23
# remove these first
24
unlink('log/user_state/bayes_seen');
25
unlink('log/user_state/bayes_toks');
26
27
# ensure it is writable by all
28
use File::Path; mkpath("log/user_state"); chmod 01777, "log/user_state";
29
30
ok(start_spamd("-L --allow-tell --paranoid"));
31
32
ok(spamcrun("-lx -L ham < data/spam/001", \&patterns_run_cb));
33
ok_all_patterns();
34
35
ok(stop_spamd());
36
37
# ensure these are not owned by root
38
ok check_owner('log/user_state/bayes_seen');
39
ok check_owner('log/user_state/bayes_toks');
40
41
sub check_owner {
42
  my $f = shift;
43
  my @stat = stat $f;
44
45
  print "stat($f) = ".join(', ', @stat)."\n";
46
47
  if (!defined $stat[1]) {
48
    warn "no stat for $f";
49
    return 0;
50
  }
51
  elsif ($stat[4] == 0) {
52
    warn "stat for $f: owner is root";
53
    return 0;
54
  }
55
  else {
56
    return 1;
57
  }
58
}
(-)t/root_spamd_x_paranoid.t (+46 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
use lib '.'; use lib 't';
4
use SATest; sa_t_init("root_spamd_x_paranoid");
5
use Test;
6
7
use constant TEST_ENABLED => conf_bool('run_root_tests');
8
use constant IS_ROOT => eval { ($> == 0); };
9
use constant RUN_TESTS => (TEST_ENABLED && IS_ROOT);
10
11
BEGIN { plan tests => (RUN_TESTS ? 14 : 0) };
12
exit unless RUN_TESTS;
13
14
# ---------------------------------------------------------------------------
15
16
%patterns = (
17
18
q{ Return-Path: sb55sb55@yahoo.com}, 'firstline',
19
q{ Subject: There yours for FREE!}, 'subj',
20
q{ X-Spam-Status: Yes, score=}, 'status',
21
q{ X-Spam-Flag: YES}, 'flag',
22
q{ X-Spam-Level: **********}, 'stars',
23
q{ TEST_ENDSNUMS}, 'endsinnums',
24
q{ TEST_NOREALNAME}, 'noreal',
25
q{ This must be the very last line}, 'lastline',
26
27
);
28
29
# run spamc as unpriv uid
30
$spamc = "sudo -u nobody $spamc";
31
32
ok(start_spamd("-L --create-prefs -x --paranoid"));
33
34
ok(spamcrun("< data/spam/001", \&patterns_run_cb));
35
ok_all_patterns();
36
37
%patterns = (
38
q{ X-Spam-Status: Yes, score=}, 'status',
39
q{ X-Spam-Flag: YES}, 'flag',
40
             );
41
42
43
ok (spamcrun("< data/spam/018", \&patterns_run_cb));
44
ok_all_patterns();
45
46
ok(stop_spamd());
(-)t/root_spamd_x.t (+46 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
use lib '.'; use lib 't';
4
use SATest; sa_t_init("root_spamd_x");
5
use Test;
6
7
use constant TEST_ENABLED => conf_bool('run_root_tests');
8
use constant IS_ROOT => eval { ($> == 0); };
9
use constant RUN_TESTS => (TEST_ENABLED && IS_ROOT);
10
11
BEGIN { plan tests => (RUN_TESTS ? 14 : 0) };
12
exit unless RUN_TESTS;
13
14
# ---------------------------------------------------------------------------
15
16
%patterns = (
17
18
q{ Return-Path: sb55sb55@yahoo.com}, 'firstline',
19
q{ Subject: There yours for FREE!}, 'subj',
20
q{ X-Spam-Status: Yes, score=}, 'status',
21
q{ X-Spam-Flag: YES}, 'flag',
22
q{ X-Spam-Level: **********}, 'stars',
23
q{ TEST_ENDSNUMS}, 'endsinnums',
24
q{ TEST_NOREALNAME}, 'noreal',
25
q{ This must be the very last line}, 'lastline',
26
27
);
28
29
# run spamc as unpriv uid
30
$spamc = "sudo -u nobody $spamc";
31
32
ok(start_spamd("-L --create-prefs -x"));
33
34
ok(spamcrun("< data/spam/001", \&patterns_run_cb));
35
ok_all_patterns();
36
37
%patterns = (
38
q{ X-Spam-Status: Yes, score=}, 'status',
39
q{ X-Spam-Flag: YES}, 'flag',
40
             );
41
42
43
ok (spamcrun("< data/spam/018", \&patterns_run_cb));
44
ok_all_patterns();
45
46
ok(stop_spamd());
(-)t/root_spamd.t (+48 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
# run with:   sudo prove -v t/root_spamd*
4
5
use lib '.'; use lib 't';
6
use SATest; sa_t_init("root_spamd");
7
use Test;
8
9
use constant TEST_ENABLED => conf_bool('run_root_tests');
10
use constant IS_ROOT => eval { ($> == 0); };
11
use constant RUN_TESTS => (TEST_ENABLED && IS_ROOT);
12
13
BEGIN { plan tests => (RUN_TESTS ? 14 : 0) };
14
exit unless RUN_TESTS;
15
16
# ---------------------------------------------------------------------------
17
18
%patterns = (
19
20
q{ Return-Path: sb55sb55@yahoo.com}, 'firstline',
21
q{ Subject: There yours for FREE!}, 'subj',
22
q{ X-Spam-Status: Yes, score=}, 'status',
23
q{ X-Spam-Flag: YES}, 'flag',
24
q{ X-Spam-Level: **********}, 'stars',
25
q{ TEST_ENDSNUMS}, 'endsinnums',
26
q{ TEST_NOREALNAME}, 'noreal',
27
q{ This must be the very last line}, 'lastline',
28
29
);
30
31
# run spamc as unpriv uid
32
$spamc = "sudo -u nobody $spamc";
33
34
ok(start_spamd("-L"));
35
36
ok(spamcrun("< data/spam/001", \&patterns_run_cb));
37
ok_all_patterns();
38
39
%patterns = (
40
q{ X-Spam-Status: Yes, score=}, 'status',
41
q{ X-Spam-Flag: YES}, 'flag',
42
             );
43
44
45
ok (spamcrun("< data/spam/018", \&patterns_run_cb));
46
ok_all_patterns();
47
48
ok(stop_spamd());
(-)t/SATest.pm (+2 lines)
Lines 138-143 Link Here
138
138
139
  $ENV{'TEST_DIR'} = $cwd;
139
  $ENV{'TEST_DIR'} = $cwd;
140
  $testname = $tname;
140
  $testname = $tname;
141
142
  $current_user = (getpwuid($>))[0];
141
}
143
}
142
144
143
# a port number between 32768 and 65535; used to allow multiple test
145
# a port number between 32768 and 65535; used to allow multiple test
(-)t/root_spamd_tell_x_paranoid.t (+58 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
use lib '.'; use lib 't';
4
use SATest; sa_t_init("root_spamd_tell_x_paranoid");
5
use Test;
6
7
use constant TEST_ENABLED => conf_bool('run_root_tests');
8
use constant IS_ROOT => eval { ($> == 0); };
9
use constant RUN_TESTS => (TEST_ENABLED && IS_ROOT);
10
11
BEGIN { plan tests => (RUN_TESTS ? 6 : 0) };
12
exit unless RUN_TESTS;
13
14
# ---------------------------------------------------------------------------
15
16
%patterns = (
17
q{ Message successfully } => 'learned',
18
);
19
20
# run spamc as unpriv uid
21
$spamc = "sudo -u nobody $spamc";
22
23
# remove these first
24
unlink('log/user_state/bayes_seen');
25
unlink('log/user_state/bayes_toks');
26
27
# ensure it is writable by all
28
use File::Path; mkpath("log/user_state"); chmod 01777, "log/user_state";
29
30
ok(start_spamd("-L --allow-tell --create-prefs -x --paranoid"));
31
32
ok(spamcrun("-lx -L ham < data/spam/001", \&patterns_run_cb));
33
ok_all_patterns();
34
35
ok(stop_spamd());
36
37
# ensure these are not owned by root
38
ok check_owner('log/user_state/bayes_seen');
39
ok check_owner('log/user_state/bayes_toks');
40
41
sub check_owner {
42
  my $f = shift;
43
  my @stat = stat $f;
44
45
  print "stat($f) = ".join(', ', @stat)."\n";
46
47
  if (!defined $stat[1]) {
48
    warn "no stat for $f";
49
    return 0;
50
  }
51
  elsif ($stat[4] == 0) {
52
    warn "stat for $f: owner is root";
53
    return 0;
54
  }
55
  else {
56
    return 1;
57
  }
58
}
(-)t/config.dist (+6 lines)
Lines 45-47 Link Here
45
# this to "y".
45
# this to "y".
46
run_spamd_prefork_stress_test=n
46
run_spamd_prefork_stress_test=n
47
47
48
# ---------------------------------------------------------------------------
49
50
# The "root_*.t" tests require root privileges, and may create files in
51
# the filesystem as part of the test.  Disabled by default.
52
run_root_tests=n
53
(-)t/spamd_allow_user_rules.t (-1 / +1 lines)
Lines 36-42 Link Here
36
";
36
";
37
close OUT;
37
close OUT;
38
38
39
ok (start_spamd ("--virtual-config-dir=log/virtualconfig/%u -L"));
39
ok (start_spamd ("--virtual-config-dir=log/virtualconfig/%u -L -u $current_user"));
40
ok (spamcrun ("-u testuser < data/spam/009", \&patterns_run_cb));
40
ok (spamcrun ("-u testuser < data/spam/009", \&patterns_run_cb));
41
ok (stop_spamd ());
41
ok (stop_spamd ());
42
42
(-)spamd/spamd.raw (-23 / +58 lines)
Lines 413-427 Link Here
413
# support setuid() to user unless:
413
# support setuid() to user unless:
414
# run with -u
414
# run with -u
415
# we're not root
415
# we're not root
416
# doing --vpopmail
416
# doing --vpopmail or --virtual-config-dir
417
# we disable user-config
417
# we disable user-config
418
my $setuid_to_user = (
418
my $setuid_to_user = (
419
	$opt{'username'} ||
419
	$opt{'username'} ||
420
	$> != 0 ||
420
	$> != 0 ||
421
	$opt{'vpopmail'} ||
421
	$opt{'vpopmail'} ||
422
	(!$opt{'user-config'} && !($opt{'setuid-with-sql'}||$opt{'setuid-with-ldap'}))
422
	$opt{'virtual-config-dir'}
423
	) ? 0 : 1;
423
      ) ? 0 : 1;
424
424
425
dbg("spamd: will perform setuids? $setuid_to_user");
426
427
if ( $opt{'vpopmail'} ) {
428
  if ( !$opt{'username'} ) {
429
    die "spamd: cannot use --vpopmail without -u\n";
430
  }
431
}
432
433
if ( $opt{'virtual-config-dir'} ) {
434
  if ( !$opt{'username'} ) {
435
    die "spamd: cannot use --virtual-config-dir without -u\n";
436
  }
437
}
438
425
# always copy the config, later code may disable
439
# always copy the config, later code may disable
426
my $copy_config_p = 1;
440
my $copy_config_p = 1;
427
441
Lines 1213-1231 Link Here
1213
    $expected_length = $hdrs->{expected_length};
1227
    $expected_length = $hdrs->{expected_length};
1214
  }
1228
  }
1215
1229
1216
  handle_setuid_to_user if ($setuid_to_user && $> == 0);
1230
  return 0 unless do_user_handling();
1231
  if ($> == 0) { die "spamd: still running as root! dying"; }
1217
1232
1218
  if ( $opt{'sql-config'} && !defined($current_user) ) {
1219
    unless ( handle_user_sql('nobody') ) {
1220
      service_unavailable_error("Error fetching user preferences via SQL");
1221
      return 0;
1222
    }
1223
  }
1224
1225
  if ( $opt{'ldap-config'} && !defined($current_user) ) {
1226
    handle_user_ldap('nobody');
1227
  }
1228
1229
  my $resp = "EX_OK";
1233
  my $resp = "EX_OK";
1230
1234
1231
  # generate mail object from input
1235
  # generate mail object from input
Lines 1389-1394 Link Here
1389
1393
1390
  $expected_length = $hdrs->{expected_length};
1394
  $expected_length = $hdrs->{expected_length};
1391
1395
1396
  return 0 unless do_user_handling();
1397
  if ($> == 0) { die "spamd: still running as root! dying"; }
1398
1392
  if (!$opt{tell}) {
1399
  if (!$opt{tell}) {
1393
    service_unavailable_error("TELL commands have not been enabled.");
1400
    service_unavailable_error("TELL commands have not been enabled.");
1394
    return 0;
1401
    return 0;
Lines 1404-1411 Link Here
1404
    return 0;
1411
    return 0;
1405
  }
1412
  }
1406
1413
1407
  &handle_setuid_to_user if ($setuid_to_user && $> == 0);
1408
1409
  if ($opt{'sql-config'} && !defined($current_user)) {
1414
  if ($opt{'sql-config'} && !defined($current_user)) {
1410
    unless (handle_user_sql('nobody')) {
1415
    unless (handle_user_sql('nobody')) {
1411
      service_unavailable_error("Error fetching user preferences via SQL");
1416
      service_unavailable_error("Error fetching user preferences via SQL");
Lines 1503-1508 Link Here
1503
1508
1504
###########################################################################
1509
###########################################################################
1505
1510
1511
sub do_user_handling {
1512
  if ($setuid_to_user && $> == 0) {
1513
    handle_setuid_to_user();
1514
  }
1515
1516
  if ( $opt{'sql-config'} && !defined($current_user) ) {
1517
    unless ( handle_user_sql('nobody') ) {
1518
      service_unavailable_error("Error fetching user preferences via SQL");
1519
      return 0;
1520
    }
1521
  }
1522
1523
  if ( $opt{'ldap-config'} && !defined($current_user) ) {
1524
    handle_user_ldap('nobody');
1525
  }
1526
1527
  dbg ("spamd: running as uid $>");
1528
  return 1;
1529
}
1530
1506
# generalised header parser.  
1531
# generalised header parser.  
1507
sub parse_headers {
1532
sub parse_headers {
1508
  my ($hdrs, $client) = @_;
1533
  my ($hdrs, $client) = @_;
Lines 1592-1600 Link Here
1592
      handle_user_setuid_with_ldap($current_user);
1617
      handle_user_setuid_with_ldap($current_user);
1593
      $setuid_to_user = 1;    # as above
1618
      $setuid_to_user = 1;    # as above
1594
    }
1619
    }
1620
    else {
1621
      handle_user_setuid_basic($current_user);
1622
    }
1595
  }
1623
  }
1596
  else {
1624
  else {
1597
    handle_user($current_user);
1625
    handle_user_setuid_basic($current_user);
1598
    if ( $opt{'sql-config'} ) {
1626
    if ( $opt{'sql-config'} ) {
1599
      unless ( handle_user_sql($current_user) ) {
1627
      unless ( handle_user_sql($current_user) ) {
1600
        service_unavailable_error("Error fetching user preferences via SQL");
1628
        service_unavailable_error("Error fetching user preferences via SQL");
Lines 1698-1704 Link Here
1698
  return 1;
1726
  return 1;
1699
}
1727
}
1700
1728
1701
sub handle_user {
1729
sub handle_user_setuid_basic {
1702
  my $username = shift;
1730
  my $username = shift;
1703
1731
1704
  #
1732
  #
Lines 1742-1747 Link Here
1742
    }
1770
    }
1743
  }
1771
  }
1744
1772
1773
  if ($opt{'user-config'}) {
1774
    handle_user_set_user_prefs($dir, $username);
1775
  }
1776
}
1777
1778
sub handle_user_set_user_prefs {
1779
  my ($dir, $username) = @_;
1780
1745
  #
1781
  #
1746
  # If vpopmail config enabled then set $dir to virtual homedir
1782
  # If vpopmail config enabled then set $dir to virtual homedir
1747
  #
1783
  #
Lines 1767-1775 Link Here
1767
  # If vpopmail config enabled then pass virtual homedir onto create_default_cf_needed
1803
  # If vpopmail config enabled then pass virtual homedir onto create_default_cf_needed
1768
  #
1804
  #
1769
  if ( $opt{'vpopmail'} ) {
1805
  if ( $opt{'vpopmail'} ) {
1770
    if ( !$opt{'username'} ) {
1771
      warn "spamd: cannot use vpopmail without -u\n";
1772
    }
1773
    create_default_cf_if_needed( $cf_file, $username, $dir );
1806
    create_default_cf_if_needed( $cf_file, $username, $dir );
1774
    $spamtest->read_scoreonly_config($cf_file);
1807
    $spamtest->read_scoreonly_config($cf_file);
1775
    $spamtest->signal_user_changed(
1808
    $spamtest->signal_user_changed(
Lines 2382-2387 Link Here
2382
The pattern B<must> expand to an absolute directory when spamd is running
2415
The pattern B<must> expand to an absolute directory when spamd is running
2383
daemonized (B<-d>).
2416
daemonized (B<-d>).
2384
2417
2418
Currently, use of this without B<-u> is not supported. This inhibits setuid.
2419
2385
=item B<-r> I<pidfile>, B<--pidfile>=I<pidfile>
2420
=item B<-r> I<pidfile>, B<--pidfile>=I<pidfile>
2386
2421
2387
Write the process ID of the spamd parent to the file specified by I<pidfile>.
2422
Write the process ID of the spamd parent to the file specified by I<pidfile>.
Lines 2395-2401 Link Here
2395
maildir.  This option is useful for vpopmail virtual users who do not have an
2430
maildir.  This option is useful for vpopmail virtual users who do not have an
2396
entry in the system /etc/passwd file.
2431
entry in the system /etc/passwd file.
2397
2432
2398
Currently, use of this without B<-u> is not supported.
2433
Currently, use of this without B<-u> is not supported. This inhibits setuid.
2399
2434
2400
=item B<-s> I<facility>, B<--syslog>=I<facility>
2435
=item B<-s> I<facility>, B<--syslog>=I<facility>
2401
2436

Return to bug 5480