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

(-)spamd/spamd.raw (-18 / +175 lines)
Lines 1083-1088 Link Here
1083
    check( $1, $2, $start, $remote_hostname, $remote_hostaddr );
1083
    check( $1, $2, $start, $remote_hostname, $remote_hostaddr );
1084
  }
1084
  }
1085
1085
1086
  elsif (/(LEARN) SPAMC\/(.*)/) {
1087
    learn( $1, $2, $start, $remote_hostname, $remote_hostaddr );
1088
  }
1089
1086
  # Looks like a client is just seeing if we're alive.
1090
  # Looks like a client is just seeing if we're alive.
1087
1091
1088
  elsif (/PING SPAMC\/(.*)/) {
1092
  elsif (/PING SPAMC\/(.*)/) {
Lines 1100-1105 Link Here
1100
  return 1;
1104
  return 1;
1101
}
1105
}
1102
1106
1107
sub handle_setuid_to_user {
1108
1109
  if ( $spamtest->{paranoid} ) {
1110
    logmsg("PARANOID: still running as root, closing connection.");
1111
    die;
1112
  }
1113
  logmsg( "Still running as root: user not specified with -u, "
1114
	  . "not found, or set to root.  Fall back to nobody." );
1115
  my ( $uid, $gid ) = ( getpwnam('nobody') )[ 2, 3 ];
1116
  $uid =~ /^(\d+)$/ and $uid = $1;    # de-taint
1117
  $gid =~ /^(\d+)$/ and $gid = $1;    # de-taint
1118
  
1119
  $) = "$gid $gid";                   # eGID
1120
  $> = $uid;                          # eUID
1121
  if ( !defined($uid) || ( $> != $uid and $> != ( $uid - 2**32 ) ) ) {
1122
    logmsg("fatal: setuid to nobody failed");
1123
    die;
1124
  }
1125
1126
}
1127
1103
sub check {
1128
sub check {
1104
  my ( $method, $version, $start_time, $remote_hostname, $remote_hostaddr ) = @_;
1129
  my ( $method, $version, $start_time, $remote_hostname, $remote_hostaddr ) = @_;
1105
  local ($_);
1130
  local ($_);
Lines 1124-1148 Link Here
1124
    $expected_length = $hdrs->{expected_length};
1149
    $expected_length = $hdrs->{expected_length};
1125
  }
1150
  }
1126
1151
1127
  if ( $setuid_to_user && $> == 0 ) {
1152
  handle_setuid_to_user if ($setuid_to_user && $> == 0);
1128
    if ( $spamtest->{paranoid} ) {
1129
      logmsg("PARANOID: still running as root, closing connection.");
1130
      die;
1131
    }
1132
    logmsg( "Still running as root: user not specified with -u, "
1133
        . "not found, or set to root.  Fall back to nobody." );
1134
    my ( $uid, $gid ) = ( getpwnam('nobody') )[ 2, 3 ];
1135
    $uid =~ /^(\d+)$/ and $uid = $1;    # de-taint
1136
    $gid =~ /^(\d+)$/ and $gid = $1;    # de-taint
1137
1153
1138
    $) = "$gid $gid";                   # eGID
1139
    $> = $uid;                          # eUID
1140
    if ( !defined($uid) || ( $> != $uid and $> != ( $uid - 2**32 ) ) ) {
1141
      logmsg("fatal: setuid to nobody failed");
1142
      die;
1143
    }
1144
  }
1145
1146
  if ( $opt{'sql-config'} && !defined($current_user) ) {
1154
  if ( $opt{'sql-config'} && !defined($current_user) ) {
1147
    unless ( handle_user_sql('nobody') ) {
1155
    unless ( handle_user_sql('nobody') ) {
1148
      service_unavailable_error("Error fetching user preferences via SQL");
1156
      service_unavailable_error("Error fetching user preferences via SQL");
Lines 1318-1323 Link Here
1318
  $mail->finish();
1326
  $mail->finish();
1319
}
1327
}
1320
1328
1329
# XXX - yuck too much shared code with check
1330
sub learn {
1331
  my ( $method, $version, $start_time, $remote_hostname, $remote_hostaddr ) = @_;
1332
  local ($_);
1333
  my $expected_length;
1334
  my $learn_type;
1335
  my $forget = 0;
1336
  my $isspam = 1;
1337
1338
  my $hdrs = {};
1339
1340
  # parse_headers returns !=0 on failure
1341
  return 1
1342
    if parse_headers(
1343
		     $hdrs, $client,
1344
		     {
1345
		      'Content-length' => \&got_clen_header,
1346
		      'User'           => \&got_user_header,
1347
		      'Learn-type'     => \&got_learn_type_header,
1348
		     }
1349
		    );
1350
1351
  $expected_length = $hdrs->{expected_length};
1352
  $learn_type = $hdrs->{learn_type};
1353
1354
  &handle_setuid_to_user if ($setuid_to_user && $> == 0);
1355
1356
  if ( $opt{'sql-config'} && !defined($current_user) ) {
1357
    unless ( handle_user_sql('nobody') ) {
1358
      service_unavailable_error("Error fetching user preferences via SQL");
1359
      return 1;
1360
    }
1361
  }
1362
1363
  if ( $opt{'ldap-config'} && !defined($current_user) ) {
1364
    handle_user_ldap('nobody');
1365
  }
1366
1367
  my $resp = "EX_OK";
1368
1369
  # Now read in message
1370
  my @msglines;
1371
  my $actual_length = 0;
1372
  while ( $_ = $client->getline() ) {
1373
    $actual_length += length($_);
1374
    push(@msglines, $_);    
1375
    last if (defined $expected_length && $actual_length >= $expected_length);
1376
  }
1377
1378
  my $mail = $spamtest->parse(\@msglines);
1379
  # Free some mem.
1380
  undef @msglines;
1381
1382
  if ( $mail->get_header("X-Spam-Checker-Version") ) {
1383
    my $new_mail = $spamtest->parse($spamtest->remove_spamassassin_markup($mail), 1);
1384
    $mail->finish();
1385
    $mail = $new_mail;
1386
  }
1387
1388
  # Extract the Message-Id(s) for logging purposes.
1389
  my $msgid  = $mail->get_pristine_header("Message-Id");
1390
  my $rmsgid = $mail->get_pristine_header("Resent-Message-Id");
1391
  foreach my $id ((\$msgid, \$rmsgid)) {
1392
    if ( $$id ) {
1393
      while ( $$id =~ s/\([^\(\)]*\)// )
1394
         { }                            # remove comments and
1395
      $$id =~ s/^\s+|\s+$//g;          # leading and trailing spaces
1396
      $$id =~ s/\s+/ /g;               # collapse whitespaces
1397
      $$id =~ s/^.*?<(.*?)>.*$/$1/;    # keep only the id itself
1398
      $$id =~ s/[^\x21-\x7e]/?/g;      # replace all weird chars
1399
      $$id =~ s/[<>]/?/g;              # plus all dangling angle brackets
1400
      $$id =~ s/^(.+)$/<$1>/;          # re-bracket the id (if not empty)
1401
    }
1402
  }
1403
1404
  $msgid        ||= "(unknown)";
1405
  $current_user ||= "(unknown)";
1406
1407
  my $learn_type_desc;
1408
  my $learn_type_desc_past;
1409
1410
  if ($learn_type == 0) {
1411
    $learn_type_desc = "learning spam";
1412
    $learn_type_desc_past = "learned spam";
1413
    $isspam = 1;
1414
  }
1415
  elsif ($learn_type == 1) {
1416
    $learn_type_desc = "learning ham";
1417
    $learn_type_desc_past = "learned ham";
1418
    $isspam = 0;
1419
  }
1420
  elsif ($learn_type == 2) {
1421
    $learn_type_desc = "forgetting";
1422
    $learn_type_desc_past = "forgot";
1423
    $forget = 1;
1424
  }
1425
1426
  logmsg( $learn_type_desc
1427
      . " message $msgid"
1428
      . ( $rmsgid ? " aka $rmsgid" : "" )
1429
      . " for ${current_user}:$>"
1430
      . "." );
1431
1432
  # Check length if we're supposed to.
1433
  if ( defined $expected_length && $actual_length != $expected_length ) {
1434
    protocol_error(
1435
      "(Content-Length mismatch: Expected $expected_length bytes, got $actual_length bytes)"
1436
    );
1437
    $mail->finish();
1438
    return 1;
1439
  }
1440
1441
  my $status = $spamtest->learn( $mail, undef, $isspam, $forget );
1442
  my $hdr;
1443
1444
  if ($status->did_learn()) {
1445
    $hdr .= "Learned: Yes";
1446
  }
1447
  else {
1448
    $hdr .= "Learned: No";
1449
  }
1450
1451
  print $client "SPAMD/1.1 $resphash{$resp} $resp\r\n",
1452
    $hdr . "\r\n\r\n";
1453
1454
  my $scantime = sprintf( "%.1f", time - $start_time );
1455
1456
1457
  logmsg( "$learn_type_desc_past message for $current_user:$> in"
1458
      . " $scantime seconds, $actual_length bytes." );
1459
  $status->finish();    # added by jm to allow GC'ing
1460
  $mail->finish();
1461
}
1462
1321
###########################################################################
1463
###########################################################################
1322
1464
1323
# generalised header parser.  
1465
# generalised header parser.  
Lines 1422-1427 Link Here
1422
  return 0;
1564
  return 0;
1423
}
1565
}
1424
1566
1567
sub got_learn_type_header {
1568
  my ( $hdrs, $header, $value ) = @_;
1569
  if ( $value !~ /^(\d*)$/ ) {
1570
    protocol_error("(Learn-type contains non-numeric bytes)");
1571
    return 1;
1572
  }
1573
  my $type = $1;
1574
  if ($type != 0 && $type != 1 && $type != 2) {
1575
    protocol_error("(Learn-type contains invalid type)");
1576
    return 1;
1577
  }
1578
  $hdrs->{learn_type} = $type;
1579
  return 0;
1580
}
1581
1425
sub protocol_error {
1582
sub protocol_error {
1426
  my ($err) = @_;
1583
  my ($err) = @_;
1427
  my $resp = "EX_PROTOCOL";
1584
  my $resp = "EX_PROTOCOL";

Return to bug 1201