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

(-)spamassassin-trunk/contrib/run-masses (-1 / +1 lines)
Lines 1-7 Link Here
1
#!/bin/sh
1
#!/bin/sh
2
2
3
# run-masses, Theo Van Dinter <felicity@kluge.net> (c) 2002
3
# run-masses, Theo Van Dinter <felicity@kluge.net> (c) 2002
4
# $Id: run-masses,v 1.1 2003/06/10 17:11:12 felicity Exp $
4
# $Id$
5
5
6
#
6
#
7
# This script will run a mass-check against all mbox files in a given
7
# This script will run a mass-check against all mbox files in a given
(-)spamassassin-trunk/spamc/libspamc.h (-3 / +10 lines)
Lines 73-78 Link Here
73
73
74
#define EX_NOTSPAM		  0
74
#define EX_NOTSPAM		  0
75
#define EX_ISSPAM		  1
75
#define EX_ISSPAM		  1
76
#define EX_LEARNED		  5
77
#define EX_NOTLEARNED	  6
76
#define EX_TOOBIG		866
78
#define EX_TOOBIG		866
77
79
78
/* Aug 14, 2002 bj: Bitflags instead of lots of bool parameters */
80
/* Aug 14, 2002 bj: Bitflags instead of lots of bool parameters */
Lines 97-102 Link Here
97
/* log to stderr */
99
/* log to stderr */
98
#define SPAMC_LOG_TO_STDERR  (1<<22)
100
#define SPAMC_LOG_TO_STDERR  (1<<22)
99
101
102
/* Nov 24, 2004 NP: added learning support */
103
#define SPAMC_LEARN  (1<<21)
104
100
/* Aug 14, 2002 bj: A struct for storing a message-in-progress */
105
/* Aug 14, 2002 bj: A struct for storing a message-in-progress */
101
typedef enum
106
typedef enum
102
{
107
{
Lines 135-140 Link Here
135
    int out_len;		/* Output from spamd. Either the filtered
140
    int out_len;		/* Output from spamd. Either the filtered
136
				   message, or the check-only response. Or else,
141
				   message, or the check-only response. Or else,
137
				   a pointer to msg above. */
142
				   a pointer to msg above. */
143
	int is_learned;	/* Output from spamd. Gives state 
144
						about learn resp. unlearn process */
138
145
139
    /* these members added in SpamAssassin version 2.60: */
146
    /* these members added in SpamAssassin version 2.60: */
140
    struct libspamc_private_message *priv;
147
    struct libspamc_private_message *priv;
Lines 204-210 Link Here
204
 * failover, more than one host is defined, but if there is only one there,
211
 * failover, more than one host is defined, but if there is only one there,
205
 * no failover is done.
212
 * no failover is done.
206
 */
213
 */
207
int message_filter(struct transport *tp, const char *username,
214
int message_filter(struct transport *tp, const char *username, int learntype,
208
		   int flags, struct message *m);
215
		   int flags, struct message *m);
209
216
210
/* Dump the message. If there is any data in the message (typically, m->type
217
/* Dump the message. If there is any data in the message (typically, m->type
Lines 216-222 Link Here
216
/* Do a message_read->message_filter->message_write sequence, handling errors
223
/* Do a message_read->message_filter->message_write sequence, handling errors
217
 * appropriately with dump_message or appropriate CHECK_ONLY output. Returns
224
 * appropriately with dump_message or appropriate CHECK_ONLY output. Returns
218
 * EX_OK or EX_ISSPAM/EX_NOTSPAM on success, some error EX on error. */
225
 * EX_OK or EX_ISSPAM/EX_NOTSPAM on success, some error EX on error. */
219
int message_process(struct transport *trans, char *username, int max_size,
226
int message_process(struct transport *trans, char *username, int learntype, int max_size,
220
		    int in_fd, int out_fd, const int flags);
227
		    int in_fd, int out_fd, const int flags);
221
228
222
/* Cleanup the resources we allocated for storing the message. Call after
229
/* Cleanup the resources we allocated for storing the message. Call after
Lines 224-230 Link Here
224
void message_cleanup(struct message *m);
231
void message_cleanup(struct message *m);
225
232
226
/* Aug 14, 2002 bj: This is now legacy, don't use it. */
233
/* Aug 14, 2002 bj: This is now legacy, don't use it. */
227
int process_message(struct transport *tp, char *username,
234
int process_message(struct transport *tp, char *username, int learntype,
228
		    int max_size, int in_fd, int out_fd,
235
		    int max_size, int in_fd, int out_fd,
229
		    const int check_only, const int safe_fallback);
236
		    const int check_only, const int safe_fallback);
230
237
(-)spamassassin-trunk/spamc/spamc.c (-15 / +53 lines)
Lines 140-146 Link Here
140
        "                      [default: 250k]\n");
140
        "                      [default: 250k]\n");
141
    usg("  -u username         User for spamd to process this message under.\n"
141
    usg("  -u username         User for spamd to process this message under.\n"
142
        "                      [default: current user]\n");
142
        "                      [default: current user]\n");
143
    
143
    usg("  -L learntype        Message gets learned as spam (0),\n"
144
		"                      or learned as ham (1), or forgotten (2)\n");
144
    usg("  -B                  Assume input is a single BSMTP-formatted\n"
145
    usg("  -B                  Assume input is a single BSMTP-formatted\n"
145
        "                      message.\n");
146
        "                      message.\n");
146
    
147
    
Lines 173-185 Link Here
173
 */
174
 */
174
int
175
int
175
read_args(int argc, char **argv,
176
read_args(int argc, char **argv,
176
          int *max_size, char **username,
177
          int *max_size, char **username, int *learntype,
177
          struct transport *ptrn)
178
          struct transport *ptrn)
178
{
179
{
179
#ifndef _WIN32
180
#ifndef _WIN32
180
    const char *opts = "-BcrRd:e:fyp:t:s:u:xSHU:ElhV";
181
    const char *opts = "-BcrRd:e:fyp:t:s:u:L:xSHU:ElhV";
181
#else
182
#else
182
    const char *opts = "-BcrRd:fyp:t:s:u:xSHElhV";
183
    const char *opts = "-BcrRd:fyp:t:s:u:L:xSHElhV";
183
#endif
184
#endif
184
    int opt;
185
    int opt;
185
    int ret = EX_OK;
186
    int ret = EX_OK;
Lines 280-285 Link Here
280
                *username = optarg;
281
                *username = optarg;
281
                break;
282
                break;
282
            }
283
            }
284
            case 'L':
285
			{
286
				flags |= SPAMC_LEARN;
287
				*learntype = atoi(optarg);
288
				break;
289
			}
283
#ifndef _WIN32
290
#ifndef _WIN32
284
            case 'U':
291
            case 'U':
285
            {
292
            {
Lines 298-304 Link Here
298
                flags |= SPAMC_SYMBOLS;
305
                flags |= SPAMC_SYMBOLS;
299
                break;
306
                break;
300
            }
307
            }
301
            
302
            case '?':
308
            case '?':
303
            case ':':
309
            case ':':
304
            {
310
            {
Lines 460-465 Link Here
460
    int out_fd = -1;
466
    int out_fd = -1;
461
    int result;
467
    int result;
462
    int ret;
468
    int ret;
469
	int learntype = 0;
463
470
464
    transport_init(&trans);
471
    transport_init(&trans);
465
472
Lines 476-487 Link Here
476
   /* Now parse the command line arguments. First, set the defaults. */
483
   /* Now parse the command line arguments. First, set the defaults. */
477
   max_size = 250 * 1024;
484
   max_size = 250 * 1024;
478
   username = NULL;
485
   username = NULL;
479
   if ((ret = read_args(argc, argv, &max_size, &username, &trans)) != EX_OK) {
486
487
   if ((ret = read_args(argc, argv, &max_size, &username, &learntype, &trans)) != EX_OK) {
480
       if (ret == EX_TEMPFAIL )
488
       if (ret == EX_TEMPFAIL )
481
           ret = EX_OK;
489
           ret = EX_OK;
482
       goto finish;
490
       goto finish;
483
   }
491
   }
484
   
492
 
485
   ret = get_current_user(&username);
493
   ret = get_current_user(&username);
486
   if (ret != EX_OK)
494
   if (ret != EX_OK)
487
       goto finish;
495
       goto finish;
Lines 518-531 Link Here
518
	
526
	
519
	if (ret == EX_OK) {
527
	if (ret == EX_OK) {
520
	    
528
	    
521
	    ret = message_filter(&trans, username, flags, &m);
529
	    ret = message_filter(&trans, username, learntype, flags, &m);
522
	    free(username); username = NULL;
530
	    free(username); username = NULL;
523
	    
524
	    if (ret == EX_OK) {
525
		get_output_fd(&out_fd);
526
531
527
		if (message_write(out_fd, &m) >= 0) {
532
		if (ret == EX_OK) {
533
			get_output_fd(&out_fd);
528
534
535
		if (flags & SPAMC_LEARN)
536
		{
537
538
			if (m.is_learned == 1)
539
			{
540
				
541
				printf( "Message successfully un/learned\n" );
542
543
				ret = EX_LEARNED;
544
545
			}
546
			else
547
			{
548
549
				printf( "Message was already un/learned\n" );
550
551
				ret = EX_NOTLEARNED;
552
553
			}
554
			message_cleanup(&m);
555
556
			goto finish;
557
558
559
		}
560
		else if (message_write(out_fd, &m) >= 0) {
561
529
		    result = m.is_spam;
562
		    result = m.is_spam;
530
                    if ((flags & SPAMC_CHECK_ONLY) && result != EX_TOOBIG) {
563
                    if ((flags & SPAMC_CHECK_ONLY) && result != EX_TOOBIG) {
531
			message_cleanup(&m);
564
			message_cleanup(&m);
Lines 559-577 Link Here
559
	message_cleanup(&m);
592
	message_cleanup(&m);
560
	ret = EX_NOTSPAM;
593
	ret = EX_NOTSPAM;
561
    }
594
    }
562
    else {
595
    else if (flags & SPAMC_LEARN )
596
	{
597
		message_cleanup(&m);
598
		ret = EX_OSERR;
599
	}
600
	else {
563
	message_dump(STDIN_FILENO, out_fd, &m);
601
	message_dump(STDIN_FILENO, out_fd, &m);
564
	message_cleanup(&m);
602
	message_cleanup(&m);
565
	if (ret == EX_TOOBIG) {
603
	if (ret == EX_TOOBIG) {
566
	    ret = 0;
604
	    ret = 0;
567
	}
605
	}
568
        else if (use_exit_code) {
606
    else if (use_exit_code) {
569
            ret = result;
607
            ret = result;
570
        }
608
        }
571
	else if (flags & SPAMC_SAFE_FALLBACK) {
609
	else if (flags & SPAMC_SAFE_FALLBACK) {
572
	    ret = EX_OK;
610
	    ret = EX_OK;
573
	}
611
	}
574
    }
612
	}
575
    
613
    
576
finish:
614
finish:
577
#ifdef _WIN32
615
#ifdef _WIN32
(-)spamassassin-trunk/spamc/libspamc.c (-11 / +78 lines)
Lines 754-759 Link Here
754
{
754
{
755
    char is_spam[6];
755
    char is_spam[6];
756
    char s_str[21], t_str[21];
756
    char s_str[21], t_str[21];
757
	char is_learned[4];
757
758
758
    UNUSED_VARIABLE(len);
759
    UNUSED_VARIABLE(len);
759
760
Lines 800-811 Link Here
800
	}
801
	}
801
	return EX_OK;
802
	return EX_OK;
802
    }
803
    }
804
	else if (sscanf(buf, "Learned: %3s", is_learned) == 1)
805
	{
806
		if(strcmp(is_learned,"yes")==0||strcmp(is_learned,"Yes")==0)
807
		{
808
			m->is_learned = 1;
809
		}
810
		else if(strcmp(is_learned,"no")==0||strcmp(is_learned,"No")==0)
811
		{
812
			m->is_learned = 0;
813
		}
814
		else
815
		{
816
			libspamc_log(flags, LOG_ERR, "spamd responded with bad Learned-state '%s'",
817
		   buf);
818
			return EX_PROTOCOL;
819
		}	    
820
		return EX_OK;
821
	}
803
822
804
    libspamc_log(flags, LOG_ERR, "spamd responded with bad header '%s'", buf);
823
    libspamc_log(flags, LOG_ERR, "spamd responded with bad header '%s'", buf);
805
    return EX_PROTOCOL;
824
    return EX_PROTOCOL;
806
}
825
}
807
826
808
int message_filter(struct transport *tp, const char *username,
827
int message_filter(struct transport *tp, const char *username, int learntype,
809
		   int flags, struct message *m)
828
		   int flags, struct message *m)
810
{
829
{
811
    char buf[8192];
830
    char buf[8192];
Lines 814-819 Link Here
814
    int sock = -1;
833
    int sock = -1;
815
    int rc;
834
    int rc;
816
    char versbuf[20];
835
    char versbuf[20];
836
	char strlearntype[1];
817
    float version;
837
    float version;
818
    int response;
838
    int response;
819
    int failureval;
839
    int failureval;
Lines 843-851 Link Here
843
    }
863
    }
844
    m->out_len = 0;
864
    m->out_len = 0;
845
865
866
    /* Build spamd protocol header */
846
867
847
    /* Build spamd protocol header */
868
	if (flags & SPAMC_CHECK_ONLY)
848
    if (flags & SPAMC_CHECK_ONLY)
849
	strcpy(buf, "CHECK ");
869
	strcpy(buf, "CHECK ");
850
    else if (flags & SPAMC_REPORT_IFSPAM)
870
    else if (flags & SPAMC_REPORT_IFSPAM)
851
	strcpy(buf, "REPORT_IFSPAM ");
871
	strcpy(buf, "REPORT_IFSPAM ");
Lines 853-859 Link Here
853
	strcpy(buf, "REPORT ");
873
	strcpy(buf, "REPORT ");
854
    else if (flags & SPAMC_SYMBOLS)
874
    else if (flags & SPAMC_SYMBOLS)
855
	strcpy(buf, "SYMBOLS ");
875
	strcpy(buf, "SYMBOLS ");
856
    else
876
    else if (flags & SPAMC_LEARN )
877
	{
878
		strcpy(buf, "LEARN ");
879
		len = strlen(buf);
880
	}
881
	else
857
	strcpy(buf, "PROCESS ");
882
	strcpy(buf, "PROCESS ");
858
883
859
    len = strlen(buf);
884
    len = strlen(buf);
Lines 868-873 Link Here
868
    strcat(buf, "\r\n");
893
    strcat(buf, "\r\n");
869
    len = strlen(buf);
894
    len = strlen(buf);
870
895
896
897
	if (flags & SPAMC_LEARN)
898
	{
899
		if ((learntype > 2) | (learntype < 0 ))
900
		{
901
		    free(m->out);
902
		    m->out = m->msg;
903
			m->out_len = m->msg_len;
904
			return EX_OSERR;
905
		}
906
		sprintf(strlearntype,"%d",learntype);
907
		strcpy(buf + len, "Learn-type: ");
908
		strcat(buf + len, strlearntype);
909
		strcat(buf + len, "\r\n");
910
		len += strlen(buf + len);
911
	}
912
871
    if (username != NULL) {
913
    if (username != NULL) {
872
	if (strlen(username) + 8 >= (bufsiz - len)) {
914
	if (strlen(username) + 8 >= (bufsiz - len)) {
873
	    free(m->out);
915
	    free(m->out);
Lines 880-886 Link Here
880
	strcat(buf + len, "\r\n");
922
	strcat(buf + len, "\r\n");
881
	len += strlen(buf + len);
923
	len += strlen(buf + len);
882
    }
924
    }
883
    if ((m->msg_len > 9999999) || ((len + 27) >= (bufsiz - len))) {
925
926
	if ((m->msg_len > 9999999) || ((len + 27) >= (bufsiz - len))) {
884
	free(m->out);
927
	free(m->out);
885
	m->out = m->msg;
928
	m->out = m->msg;
886
	m->out_len = m->msg_len;
929
	m->out_len = m->msg_len;
Lines 948-953 Link Here
948
    m->score = 0;
991
    m->score = 0;
949
    m->threshold = 0;
992
    m->threshold = 0;
950
    m->is_spam = EX_TOOBIG;
993
    m->is_spam = EX_TOOBIG;
994
	m->is_learned = 0;
951
    while (1) {
995
    while (1) {
952
	failureval =
996
	failureval =
953
	    _spamc_read_full_line(m, flags, ssl, sock, buf, &len, bufsiz);
997
	    _spamc_read_full_line(m, flags, ssl, sock, buf, &len, bufsiz);
Lines 960-966 Link Here
960
	}
1004
	}
961
1005
962
	if (_handle_spamd_header(m, flags, buf, len) < 0) {
1006
	if (_handle_spamd_header(m, flags, buf, len) < 0) {
963
	    failureval = EX_PROTOCOL;
1007
		failureval = EX_PROTOCOL;
964
	    goto failure;
1008
	    goto failure;
965
	}
1009
	}
966
    }
1010
    }
Lines 977-986 Link Here
977
	}
1021
	}
978
	return EX_OK;
1022
	return EX_OK;
979
    }
1023
    }
1024
	else if (flags & SPAMC_LEARN)
1025
	{
1026
		shutdown(sock, SHUT_RD);
1027
		closesocket(sock);
1028
		sock = -1;
1029
		return EX_OK;
1030
	}
980
    else {
1031
    else {
981
	if (m->content_length < 0) {
1032
	if (m->content_length < 0) {
982
	    /* should have got a length too. */
1033
	    /* should have got a length too. */
983
	    failureval = EX_PROTOCOL;
1034
		
1035
		failureval = EX_PROTOCOL;
984
	    goto failure;
1036
	    goto failure;
985
	}
1037
	}
986
1038
Lines 1048-1054 Link Here
1048
}
1100
}
1049
1101
1050
1102
1051
int message_process(struct transport *trans, char *username, int max_size,
1103
int message_process(struct transport *trans, char *username, int learntype, int max_size,
1052
		    int in_fd, int out_fd, const int flags)
1104
		    int in_fd, int out_fd, const int flags)
1053
{
1105
{
1054
    int ret;
1106
    int ret;
Lines 1060-1066 Link Here
1060
    ret = message_read(in_fd, flags, &m);
1112
    ret = message_read(in_fd, flags, &m);
1061
    if (ret != EX_OK)
1113
    if (ret != EX_OK)
1062
	goto FAIL;
1114
	goto FAIL;
1063
    ret = message_filter(trans, username, flags, &m);
1115
    ret = message_filter(trans, username, learntype, flags, &m);
1064
    if (ret != EX_OK)
1116
    if (ret != EX_OK)
1065
	goto FAIL;
1117
	goto FAIL;
1066
    if (message_write(out_fd, &m) < 0)
1118
    if (message_write(out_fd, &m) < 0)
Lines 1085-1090 Link Here
1085
    }
1137
    }
1086
}
1138
}
1087
1139
1140
1088
void message_cleanup(struct message *m)
1141
void message_cleanup(struct message *m)
1089
{
1142
{
1090
    if (m->out != NULL && m->pre != NULL && m->out != m->pre+m->pre_len)
1143
    if (m->out != NULL && m->pre != NULL && m->out != m->pre+m->pre_len)
Lines 1097-1103 Link Here
1097
}
1150
}
1098
1151
1099
/* Aug 14, 2002 bj: Obsolete! */
1152
/* Aug 14, 2002 bj: Obsolete! */
1100
int process_message(struct transport *tp, char *username, int max_size,
1153
int process_message(struct transport *tp, char *username, int learntype, int max_size,
1101
		    int in_fd, int out_fd, const int my_check_only,
1154
		    int in_fd, int out_fd, const int my_check_only,
1102
		    const int my_safe_fallback)
1155
		    const int my_safe_fallback)
1103
{
1156
{
Lines 1109-1115 Link Here
1109
    if (my_safe_fallback)
1162
    if (my_safe_fallback)
1110
	flags |= SPAMC_SAFE_FALLBACK;
1163
	flags |= SPAMC_SAFE_FALLBACK;
1111
1164
1112
    return message_process(tp, username, max_size, in_fd, out_fd, flags);
1165
    return message_process(tp, username, learntype, max_size, in_fd, out_fd, flags);
1113
}
1166
}
1114
1167
1115
/*
1168
/*
Lines 1389-1392 Link Here
1389
    exit(0);
1442
    exit(0);
1390
}
1443
}
1391
1444
1445
1446
1447
1392
#endif /* LIBSPAMC_UNIT_TESTS */
1448
#endif /* LIBSPAMC_UNIT_TESTS */
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
(-)spamassassin-trunk/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