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

(-)spamc/libspamc.h (-5 / +11 lines)
Lines 139-146 Link Here
139
    int out_len;		/* Output from spamd. Either the filtered
139
    int out_len;		/* Output from spamd. Either the filtered
140
				   message, or the check-only response. Or else,
140
				   message, or the check-only response. Or else,
141
				   a pointer to msg above. */
141
				   a pointer to msg above. */
142
    int is_learned;	        /* Output from spamd. Gives state
143
				   about learn resp. unlearn process */
144
142
145
    /* these members added in SpamAssassin version 2.60: */
143
    /* these members added in SpamAssassin version 2.60: */
146
    struct libspamc_private_message *priv;
144
    struct libspamc_private_message *priv;
Lines 210-218 Link Here
210
 * failover, more than one host is defined, but if there is only one there,
208
 * failover, more than one host is defined, but if there is only one there,
211
 * no failover is done.
209
 * no failover is done.
212
 */
210
 */
213
int message_filter(struct transport *tp, const char *username, int learntype,
211
int message_filter(struct transport *tp, const char *username,
214
		   int flags, struct message *m);
212
		   int flags, struct message *m);
215
213
214
/* Process the message through the spamd learn, making as many connection
215
 * attempts as are implied by the transport structure. To make this do
216
 * failover, more than one host is defined, but if there is only one there,
217
 * no failover is done.
218
 */
219
int message_learn(struct transport *tp, const char *username, int flags,
220
		  struct message *m, int learntype, int *islearned);
221
216
/* Dump the message. If there is any data in the message (typically, m->type
222
/* Dump the message. If there is any data in the message (typically, m->type
217
 * will be MESSAGE_ERROR) it will be message_writed. Then, fd_in will be piped
223
 * will be MESSAGE_ERROR) it will be message_writed. Then, fd_in will be piped
218
 * to fd_out intol EOF. This is particularly useful if you get back an
224
 * to fd_out intol EOF. This is particularly useful if you get back an
Lines 222-228 Link Here
222
/* Do a message_read->message_filter->message_write sequence, handling errors
228
/* Do a message_read->message_filter->message_write sequence, handling errors
223
 * appropriately with dump_message or appropriate CHECK_ONLY output. Returns
229
 * appropriately with dump_message or appropriate CHECK_ONLY output. Returns
224
 * EX_OK or EX_ISSPAM/EX_NOTSPAM on success, some error EX on error. */
230
 * EX_OK or EX_ISSPAM/EX_NOTSPAM on success, some error EX on error. */
225
int message_process(struct transport *trans, char *username, int learntype, int max_size,
231
int message_process(struct transport *trans, char *username, int max_size,
226
		    int in_fd, int out_fd, const int flags);
232
		    int in_fd, int out_fd, const int flags);
227
233
228
/* Cleanup the resources we allocated for storing the message. Call after
234
/* Cleanup the resources we allocated for storing the message. Call after
Lines 230-236 Link Here
230
void message_cleanup(struct message *m);
236
void message_cleanup(struct message *m);
231
237
232
/* Aug 14, 2002 bj: This is now legacy, don't use it. */
238
/* Aug 14, 2002 bj: This is now legacy, don't use it. */
233
int process_message(struct transport *tp, char *username, int learntype,
239
int process_message(struct transport *tp, char *username,
234
		    int max_size, int in_fd, int out_fd,
240
		    int max_size, int in_fd, int out_fd,
235
		    const int check_only, const int safe_fallback);
241
		    const int check_only, const int safe_fallback);
236
242
(-)spamc/spamc.c (-2 / +8 lines)
Lines 501-506 Link Here
501
    int result;
501
    int result;
502
    int ret;
502
    int ret;
503
    int learntype = 0;
503
    int learntype = 0;
504
    int islearned = 0;
504
505
505
    transport_init(&trans);
506
    transport_init(&trans);
506
507
Lines 560-566 Link Here
560
561
561
	if (ret == EX_OK) {
562
	if (ret == EX_OK) {
562
563
563
	    ret = message_filter(&trans, username, learntype, flags, &m);
564
 	    if (flags & SPAMC_LEARN) {
565
	      ret = message_learn(&trans, username, flags, &m, learntype, &islearned);
566
	    }
567
	    else {
568
	      ret = message_filter(&trans, username, flags, &m);
569
	    }
564
570
565
	    free(username); username = NULL;
571
	    free(username); username = NULL;
566
	    
572
	    
Lines 569-575 Link Here
569
		get_output_fd(&out_fd);
575
		get_output_fd(&out_fd);
570
576
571
		if (flags & SPAMC_LEARN) {
577
		if (flags & SPAMC_LEARN) {
572
		    if (m.is_learned == 1) {
578
		    if (islearned == 1) {
573
  		        printf("Message successfully un/learned\n");
579
  		        printf("Message successfully un/learned\n");
574
		    }
580
		    }
575
		    else {
581
		    else {
(-)spamc/libspamc.c (-39 / +206 lines)
Lines 765-771 Link Here
765
}
765
}
766
766
767
static int
767
static int
768
_handle_spamd_header(struct message *m, int flags, char *buf, int len)
768
_handle_spamd_header(struct message *m, int flags, char *buf, int len,
769
		     int *islearned)
769
{
770
{
770
    char is_spam[6];
771
    char is_spam[6];
771
    char s_str[21], t_str[21];
772
    char s_str[21], t_str[21];
Lines 818-827 Link Here
818
    }
819
    }
819
    else if (sscanf(buf, "Learned: %3s", is_learned) == 1) {
820
    else if (sscanf(buf, "Learned: %3s", is_learned) == 1) {
820
        if(strcmp(is_learned, "yes") == 0 || strcmp(is_learned, "Yes") == 0) {
821
        if(strcmp(is_learned, "yes") == 0 || strcmp(is_learned, "Yes") == 0) {
821
	  m->is_learned = 1;
822
	  *islearned = 1;
822
	}
823
	}
823
	else if(strcmp(is_learned, "no") == 0 || strcmp(is_learned, "No") == 0) {
824
	else if(strcmp(is_learned, "no") == 0 || strcmp(is_learned, "No") == 0) {
824
	  m->is_learned = 0;
825
	  *islearned = 0;
825
	}
826
	}
826
	else {
827
	else {
827
	  libspamc_log(flags, LOG_ERR, "spamd responded with bad Learned-state '%s'",
828
	  libspamc_log(flags, LOG_ERR, "spamd responded with bad Learned-state '%s'",
Lines 835-842 Link Here
835
    return EX_PROTOCOL;
836
    return EX_PROTOCOL;
836
}
837
}
837
838
838
int message_filter(struct transport *tp, const char *username, int learntype,
839
int message_filter(struct transport *tp, const char *username,
839
		   int flags, struct message *m)
840
                   int flags, struct message *m)
840
{
841
{
841
    char buf[8192];
842
    char buf[8192];
842
    size_t bufsiz = (sizeof(buf) / sizeof(*buf)) - 4; /* bit of breathing room */
843
    size_t bufsiz = (sizeof(buf) / sizeof(*buf)) - 4; /* bit of breathing room */
Lines 844-850 Link Here
844
    int sock = -1;
845
    int sock = -1;
845
    int rc;
846
    int rc;
846
    char versbuf[20];
847
    char versbuf[20];
847
    char strlearntype[1];
848
    float version;
848
    float version;
849
    int response;
849
    int response;
850
    int failureval;
850
    int failureval;
Lines 876-882 Link Here
876
    m->out_len = 0;
876
    m->out_len = 0;
877
877
878
    /* Build spamd protocol header */
878
    /* Build spamd protocol header */
879
    if(flags & SPAMC_CHECK_ONLY)
879
    if (flags & SPAMC_CHECK_ONLY)
880
	strcpy(buf, "CHECK ");
880
	strcpy(buf, "CHECK ");
881
    else if (flags & SPAMC_REPORT_IFSPAM)
881
    else if (flags & SPAMC_REPORT_IFSPAM)
882
	strcpy(buf, "REPORT_IFSPAM ");
882
	strcpy(buf, "REPORT_IFSPAM ");
Lines 884-891 Link Here
884
	strcpy(buf, "REPORT ");
884
	strcpy(buf, "REPORT ");
885
    else if (flags & SPAMC_SYMBOLS)
885
    else if (flags & SPAMC_SYMBOLS)
886
	strcpy(buf, "SYMBOLS ");
886
	strcpy(buf, "SYMBOLS ");
887
    else if (flags & SPAMC_LEARN )
888
        strcpy(buf, "LEARN ");
889
    else
887
    else
890
	strcpy(buf, "PROCESS ");
888
	strcpy(buf, "PROCESS ");
891
889
Lines 899-919 Link Here
899
    strcat(buf, "\r\n");
897
    strcat(buf, "\r\n");
900
    len = strlen(buf);
898
    len = strlen(buf);
901
899
902
903
    if (flags & SPAMC_LEARN) {
904
        if ((learntype > 2) | (learntype < 0 )) {
905
	  free(m->out);
906
  	  m->out = m->msg;
907
  	  m->out_len = m->msg_len;
908
	  return EX_OSERR;
909
	}
910
	sprintf(strlearntype,"%d",learntype);
911
	strcpy(buf + len, "Learn-type: ");
912
	strcat(buf + len, strlearntype);
913
	strcat(buf + len, "\r\n");
914
	len += strlen(buf + len);
915
    }
916
917
    if (username != NULL) {
900
    if (username != NULL) {
918
	if (strlen(username) + 8 >= (bufsiz - len)) {
901
	if (strlen(username) + 8 >= (bufsiz - len)) {
919
	    _use_msg_for_out(m);
902
	    _use_msg_for_out(m);
Lines 988-994 Link Here
988
    m->score = 0;
971
    m->score = 0;
989
    m->threshold = 0;
972
    m->threshold = 0;
990
    m->is_spam = EX_TOOBIG;
973
    m->is_spam = EX_TOOBIG;
991
    m->is_learned = 0;
992
    while (1) {
974
    while (1) {
993
	failureval =
975
	failureval =
994
	    _spamc_read_full_line(m, flags, ssl, sock, buf, &len, bufsiz);
976
	    _spamc_read_full_line(m, flags, ssl, sock, buf, &len, bufsiz);
Lines 999-1006 Link Here
999
	if (len == 0 && buf[0] == '\0') {
981
	if (len == 0 && buf[0] == '\0') {
1000
	    break;		/* end of headers */
982
	    break;		/* end of headers */
1001
	}
983
	}
1002
984
	int throwaway;
1003
	if (_handle_spamd_header(m, flags, buf, len) < 0) {
985
	if (_handle_spamd_header(m, flags, buf, len, &throwaway) < 0) {
1004
	    failureval = EX_PROTOCOL;
986
	    failureval = EX_PROTOCOL;
1005
	    goto failure;
987
	    goto failure;
1006
	}
988
	}
Lines 1018-1029 Link Here
1018
	}
1000
	}
1019
	return EX_OK;
1001
	return EX_OK;
1020
    }
1002
    }
1021
    else if (flags & SPAMC_LEARN) {
1022
        shutdown(sock, SHUT_RD);
1023
	closesocket(sock);
1024
	sock = -1;
1025
	return EX_OK;
1026
    }
1027
    else {
1003
    else {
1028
	if (m->content_length < 0) {
1004
	if (m->content_length < 0) {
1029
	    /* should have got a length too. */
1005
	    /* should have got a length too. */
Lines 1093-1099 Link Here
1093
}
1069
}
1094
1070
1095
1071
1096
int message_process(struct transport *trans, char *username, int learntype, int max_size,
1072
int message_process(struct transport *trans, char *username, int max_size,
1097
		    int in_fd, int out_fd, const int flags)
1073
		    int in_fd, int out_fd, const int flags)
1098
{
1074
{
1099
    int ret;
1075
    int ret;
Lines 1105-1111 Link Here
1105
    ret = message_read(in_fd, flags, &m);
1081
    ret = message_read(in_fd, flags, &m);
1106
    if (ret != EX_OK)
1082
    if (ret != EX_OK)
1107
        goto FAIL;
1083
        goto FAIL;
1108
    ret = message_filter(trans, username, learntype, flags, &m);
1084
    ret = message_filter(trans, username, flags, &m);
1109
    if (ret != EX_OK)
1085
    if (ret != EX_OK)
1110
        goto FAIL;
1086
        goto FAIL;
1111
    if (message_write(out_fd, &m) < 0)
1087
    if (message_write(out_fd, &m) < 0)
Lines 1130-1136 Link Here
1130
    }
1106
    }
1131
}
1107
}
1132
1108
1109
int message_learn(struct transport *tp, const char *username, int flags,
1110
		  struct message *m, int learntype, int *islearned)
1111
{
1112
    char buf[8192];
1113
    size_t bufsiz = (sizeof(buf) / sizeof(*buf)) - 4; /* bit of breathing room */
1114
    size_t len;
1115
    int sock = -1;
1116
    int rc;
1117
    char versbuf[20];
1118
    char strlearntype[1];
1119
    float version;
1120
    int response;
1121
    int failureval;
1122
    SSL_CTX *ctx = NULL;
1123
    SSL *ssl = NULL;
1124
    SSL_METHOD *meth;
1133
1125
1126
    if (flags & SPAMC_USE_SSL) {
1127
#ifdef SPAMC_SSL
1128
	SSLeay_add_ssl_algorithms();
1129
	meth = SSLv2_client_method();
1130
	SSL_load_error_strings();
1131
	ctx = SSL_CTX_new(meth);
1132
#else
1133
	UNUSED_VARIABLE(ssl);
1134
	UNUSED_VARIABLE(meth);
1135
	UNUSED_VARIABLE(ctx);
1136
	libspamc_log(flags, LOG_ERR, "spamc not built with SSL support");
1137
	return EX_SOFTWARE;
1138
#endif
1139
    }
1140
1141
    m->is_spam = EX_TOOBIG;
1142
    if ((m->outbuf = malloc(m->max_len + EXPANSION_ALLOWANCE + 1)) == NULL) {
1143
	failureval = EX_OSERR;
1144
	goto failure;
1145
    }
1146
    m->out = m->outbuf;
1147
    m->out_len = 0;
1148
1149
    /* Build spamd protocol header */
1150
    strcpy(buf, "LEARN ");
1151
1152
    len = strlen(buf);
1153
    if (len + strlen(PROTOCOL_VERSION) + 2 >= bufsiz) {
1154
	_use_msg_for_out(m);
1155
	return EX_OSERR;
1156
    }
1157
1158
    strcat(buf, PROTOCOL_VERSION);
1159
    strcat(buf, "\r\n");
1160
    len = strlen(buf);
1161
1162
    if ((learntype > 2) | (learntype < 0 )) {
1163
      free(m->out);
1164
      m->out = m->msg;
1165
      m->out_len = m->msg_len;
1166
      return EX_OSERR;
1167
    }
1168
    sprintf(strlearntype,"%d",learntype);
1169
    strcpy(buf + len, "Learn-type: ");
1170
    strcat(buf + len, strlearntype);
1171
    strcat(buf + len, "\r\n");
1172
    len += strlen(buf + len);
1173
1174
    if (username != NULL) {
1175
	if (strlen(username) + 8 >= (bufsiz - len)) {
1176
	    _use_msg_for_out(m);
1177
	    return EX_OSERR;
1178
	}
1179
	strcpy(buf + len, "User: ");
1180
	strcat(buf + len, username);
1181
	strcat(buf + len, "\r\n");
1182
	len += strlen(buf + len);
1183
    }
1184
    if ((m->msg_len > 9999999) || ((len + 27) >= (bufsiz - len))) {
1185
	_use_msg_for_out(m);
1186
	return EX_OSERR;
1187
    }
1188
    len += sprintf(buf + len, "Content-length: %d\r\n\r\n", m->msg_len);
1189
1190
    libspamc_timeout = m->timeout;
1191
1192
    if (tp->socketpath)
1193
	rc = _try_to_connect_unix(tp, &sock);
1194
    else
1195
	rc = _try_to_connect_tcp(tp, &sock);
1196
1197
    if (rc != EX_OK) {
1198
	_use_msg_for_out(m);
1199
	return rc;      /* use the error code try_to_connect_*() gave us. */
1200
    }
1201
1202
    if (flags & SPAMC_USE_SSL) {
1203
#ifdef SPAMC_SSL
1204
	ssl = SSL_new(ctx);
1205
	SSL_set_fd(ssl, sock);
1206
	SSL_connect(ssl);
1207
#endif
1208
    }
1209
1210
    /* Send to spamd */
1211
    if (flags & SPAMC_USE_SSL) {
1212
#ifdef SPAMC_SSL
1213
	SSL_write(ssl, buf, len);
1214
	SSL_write(ssl, m->msg, m->msg_len);
1215
#endif
1216
    }
1217
    else {
1218
	full_write(sock, 0, buf, len);
1219
	full_write(sock, 0, m->msg, m->msg_len);
1220
	shutdown(sock, SHUT_WR);
1221
    }
1222
1223
    /* ok, now read and parse it.  SPAMD/1.2 line first... */
1224
    failureval =
1225
	_spamc_read_full_line(m, flags, ssl, sock, buf, &len, bufsiz);
1226
    if (failureval != EX_OK) {
1227
	goto failure;
1228
    }
1229
1230
    if (sscanf(buf, "SPAMD/%18s %d %*s", versbuf, &response) != 2) {
1231
	libspamc_log(flags, LOG_ERR, "spamd responded with bad string '%s'", buf);
1232
	failureval = EX_PROTOCOL;
1233
	goto failure;
1234
    }
1235
1236
    versbuf[19] = '\0';
1237
    version = _locale_safe_string_to_float(versbuf, 20);
1238
    if (version < 1.0) {
1239
	libspamc_log(flags, LOG_ERR, "spamd responded with bad version string '%s'",
1240
	       versbuf);
1241
	failureval = EX_PROTOCOL;
1242
	goto failure;
1243
    }
1244
1245
    m->score = 0;
1246
    m->threshold = 0;
1247
    m->is_spam = EX_TOOBIG;
1248
    *islearned = 0;
1249
    while (1) {
1250
	failureval =
1251
	    _spamc_read_full_line(m, flags, ssl, sock, buf, &len, bufsiz);
1252
	if (failureval != EX_OK) {
1253
	    goto failure;
1254
	}
1255
1256
	if (len == 0 && buf[0] == '\0') {
1257
	    break;		/* end of headers */
1258
	}
1259
1260
	if (_handle_spamd_header(m, flags, buf, len, islearned) < 0) {
1261
	    failureval = EX_PROTOCOL;
1262
	    goto failure;
1263
	}
1264
    }
1265
1266
    len = 0;			/* overwrite those headers */
1267
1268
    shutdown(sock, SHUT_RD);
1269
    closesocket(sock);
1270
    sock = -1;
1271
    return EX_OK;
1272
1273
    libspamc_timeout = 0;
1274
1275
    if (m->out_len != m->content_length) {
1276
	libspamc_log(flags, LOG_ERR,
1277
	       "failed sanity check, %d bytes claimed, %d bytes seen",
1278
	       m->content_length, m->out_len);
1279
	failureval = EX_PROTOCOL;
1280
	goto failure;
1281
    }
1282
1283
    return EX_OK;
1284
1285
  failure:
1286
	_use_msg_for_out(m);
1287
    if (sock != -1) {
1288
	closesocket(sock);
1289
    }
1290
    libspamc_timeout = 0;
1291
1292
    if (flags & SPAMC_USE_SSL) {
1293
#ifdef SPAMC_SSL
1294
	SSL_free(ssl);
1295
	SSL_CTX_free(ctx);
1296
#endif
1297
    }
1298
    return failureval;
1299
}
1300
1134
void message_cleanup(struct message *m)
1301
void message_cleanup(struct message *m)
1135
{
1302
{
1136
    if (m->outbuf)
1303
    if (m->outbuf)
Lines 1143-1151 Link Here
1143
}
1310
}
1144
1311
1145
/* Aug 14, 2002 bj: Obsolete! */
1312
/* Aug 14, 2002 bj: Obsolete! */
1146
int process_message(struct transport *tp, char *username, int learntype,
1313
int process_message(struct transport *tp, char *username, int max_size,
1147
		    int max_size, int in_fd, int out_fd,
1314
		    int in_fd, int out_fd, const int my_check_only,
1148
		    const int my_check_only, const int my_safe_fallback)
1315
		    const int my_safe_fallback)
1149
{
1316
{
1150
    int flags;
1317
    int flags;
1151
1318
Lines 1155-1161 Link Here
1155
    if (my_safe_fallback)
1322
    if (my_safe_fallback)
1156
        flags |= SPAMC_SAFE_FALLBACK;
1323
        flags |= SPAMC_SAFE_FALLBACK;
1157
1324
1158
    return message_process(tp, username, learntype, max_size, in_fd, out_fd, flags);
1325
    return message_process(tp, username, max_size, in_fd, out_fd, flags);
1159
}
1326
}
1160
1327
1161
/*
1328
/*

Return to bug 1201