You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

patch-exim-src_spam.c.diff 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. diff -ru exim-4.70.orig/src/expand.c exim-4.70/src/expand.c
  2. --- exim-4.70.orig/src/expand.c 2016-04-09 13:42:00.227625074 +0200
  3. +++ exim-4.70/src/expand.c 2016-04-09 13:42:37.183633096 +0200
  4. @@ -578,6 +578,7 @@
  5. { "sn8", vtype_filter_int, &filter_sn[8] },
  6. { "sn9", vtype_filter_int, &filter_sn[9] },
  7. #ifdef WITH_CONTENT_SCAN
  8. + { "spam_action", vtype_stringptr, &spam_action },
  9. { "spam_bar", vtype_stringptr, &spam_bar },
  10. { "spam_report", vtype_stringptr, &spam_report },
  11. { "spam_score", vtype_stringptr, &spam_score },
  12. diff -ru exim-4.70.orig/src/globals.c exim-4.70/src/globals.c
  13. --- exim-4.70.orig/src/globals.c 2016-04-09 13:42:00.219625073 +0200
  14. +++ exim-4.70/src/globals.c 2016-04-09 13:42:37.187633096 +0200
  15. @@ -1136,6 +1136,7 @@
  16. uschar *spamd_address = US"127.0.0.1 783";
  17. uschar *spam_bar = NULL;
  18. uschar *spam_report = NULL;
  19. +uschar *spam_action = NULL;
  20. uschar *spam_score = NULL;
  21. uschar *spam_score_int = NULL;
  22. #endif
  23. diff -ru exim-4.70.orig/src/globals.h exim-4.70/src/globals.h
  24. --- exim-4.70.orig/src/globals.h 2016-04-09 13:42:00.219625073 +0200
  25. +++ exim-4.70/src/globals.h 2016-04-09 13:42:37.187633096 +0200
  26. @@ -703,6 +703,7 @@
  27. extern uschar *spamd_address; /* address for the spamassassin daemon */
  28. extern uschar *spam_bar; /* the spam "bar" (textual representation of spam_score) */
  29. extern uschar *spam_report; /* the spamd report (multiline) */
  30. +extern uschar *spam_action; /* the spamd action */
  31. extern uschar *spam_score; /* the spam score (float) */
  32. extern uschar *spam_score_int; /* spam_score * 10 (int) */
  33. #endif
  34. diff -ru exim-4.70.orig/src/spam.c exim-4.70/src/spam.c
  35. --- exim-4.70.orig/src/spam.c 2016-04-09 13:42:00.231625075 +0200
  36. +++ exim-4.70/src/spam.c 2016-04-09 13:43:43.927647677 +0200
  37. @@ -16,6 +16,7 @@
  38. uschar spam_score_buffer[16];
  39. uschar spam_score_int_buffer[16];
  40. uschar spam_bar_buffer[128];
  41. +uschar spam_action_buffer[32];
  42. uschar spam_report_buffer[32600];
  43. uschar prev_user_name[128] = "";
  44. int spam_ok = 0;
  45. @@ -31,9 +32,11 @@
  46. int spamd_sock;
  47. uschar spamd_buffer[32600];
  48. int i, j, offset, result;
  49. + BOOL is_rspamd;
  50. uschar spamd_version[8];
  51. + uschar spamd_short_result[8];
  52. uschar spamd_score_char;
  53. - double spamd_threshold, spamd_score;
  54. + double spamd_threshold, spamd_score, spamd_reject_score;
  55. int spamd_report_offset;
  56. uschar *p,*q;
  57. int override = 0;
  58. @@ -122,8 +125,15 @@
  59. spamd_address_container *this_spamd =
  60. (spamd_address_container *)store_get(sizeof(spamd_address_container));
  61. + /* Check for spamd variant */
  62. + if( Ustrstr(address, "variant=rspamd") != NULL ) {
  63. + this_spamd->is_rspamd = TRUE;
  64. + }
  65. + else {
  66. + this_spamd->is_rspamd = FALSE;
  67. + }
  68. /* grok spamd address and port */
  69. - if( sscanf(CS address, "%s %u", this_spamd->tcp_addr, &(this_spamd->tcp_port)) != 2 ) {
  70. + if( sscanf(CS address, "%23s %hu", this_spamd->tcp_addr, &(this_spamd->tcp_port)) != 2 ) {
  71. log_write(0, LOG_MAIN,
  72. "spam acl condition: warning - invalid spamd address: '%s'", address);
  73. continue;
  74. @@ -165,6 +175,7 @@
  75. spamd_address_vector[current_server]->tcp_port,
  76. 5 ) > -1) {
  77. /* connection OK */
  78. + is_rspamd = spamd_address_vector[current_server]->is_rspamd;
  79. break;
  80. };
  81. @@ -197,12 +208,28 @@
  82. }
  83. server.sun_family = AF_UNIX;
  84. - Ustrcpy(server.sun_path, spamd_address_work);
  85. + p = Ustrstr(spamd_address_work, "variant=rspamd");
  86. + if( p != NULL ) {
  87. + is_rspamd = TRUE;
  88. + /* strip spaces */
  89. + p --;
  90. + while (p > spamd_address_work && isspace (*p)) {
  91. + p --;
  92. + }
  93. + Ustrncpy(server.sun_path, spamd_address_work, p - spamd_address_work + 1);
  94. + /* zero terminate */
  95. + server.sun_path[p - spamd_address_work + 1] = 0;
  96. + }
  97. + else {
  98. + is_rspamd = FALSE;
  99. + Ustrcpy(server.sun_path, spamd_address_work);
  100. + }
  101. +
  102. if (connect(spamd_sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) < 0) {
  103. log_write(0, LOG_MAIN|LOG_PANIC,
  104. "malware acl condition: spamd: unable to connect to UNIX socket %s (%s)",
  105. - spamd_address_work, strerror(errno) );
  106. + server.sun_path, strerror(errno) );
  107. (void)fclose(mbox_file);
  108. (void)close(spamd_sock);
  109. return DEFER;
  110. @@ -210,22 +237,50 @@
  111. }
  112. + (void)fcntl(spamd_sock, F_SETFL, O_NONBLOCK);
  113. /* now we are connected to spamd on spamd_sock */
  114. - (void)string_format(spamd_buffer,
  115. - sizeof(spamd_buffer),
  116. - "REPORT SPAMC/1.2\r\nUser: %s\r\nContent-length: %ld\r\n\r\n",
  117. - user_name,
  118. - mbox_size);
  119. -
  120. - /* send our request */
  121. - if (send(spamd_sock, spamd_buffer, Ustrlen(spamd_buffer), 0) < 0) {
  122. + if (is_rspamd) {
  123. + /* rspamd variant */
  124. + const char *helo;
  125. + const char *fcrdns;
  126. + const char *authid;
  127. + uschar *req_str;
  128. +
  129. + req_str = string_sprintf("CHECK RSPAMC/1.3\r\nContent-length: %lu\r\n"
  130. + "Queue-Id: %s\r\nFrom: <%s>\r\nRecipient-Number: %d\r\n", mbox_size,
  131. + message_id, sender_address, recipients_count);
  132. + for (i = 0; i < recipients_count; i ++)
  133. + req_str = string_sprintf("%sRcpt: <%s>\r\n", req_str, recipients_list[i].address);
  134. + if ((helo = expand_string(US"$sender_helo_name")) != NULL && *helo != '\0')
  135. + req_str = string_sprintf("%sHelo: %s\r\n", req_str, helo);
  136. + if ((fcrdns = expand_string(US"$sender_host_name")) != NULL && *fcrdns != '\0')
  137. + req_str = string_sprintf("%sHostname: %s\r\n", req_str, fcrdns);
  138. + if (sender_host_address != NULL)
  139. + req_str = string_sprintf("%sIP: %s\r\n", req_str, sender_host_address);
  140. + if ((authid = expand_string(US"$authenticated_id")) != NULL && *authid != '\0')
  141. + req_str = string_sprintf("%sUser: %s\r\n", req_str, authid);
  142. + req_str = string_sprintf("%s\r\n", req_str);
  143. + wrote = send(spamd_sock, req_str, Ustrlen(req_str), 0);
  144. + }
  145. + else {
  146. + /* spamassassin variant */
  147. + (void)string_format(spamd_buffer,
  148. + sizeof(spamd_buffer),
  149. + "REPORT SPAMC/1.2\r\nUser: %s\r\nContent-length: %ld\r\n\r\n",
  150. + user_name,
  151. + mbox_size);
  152. + /* send our request */
  153. + wrote = send(spamd_sock, spamd_buffer, Ustrlen(spamd_buffer), 0);
  154. + }
  155. + if(wrote == -1)
  156. + {
  157. (void)close(spamd_sock);
  158. log_write(0, LOG_MAIN|LOG_PANIC,
  159. - "spam acl condition: spamd send failed: %s", strerror(errno));
  160. + "spam acl condition: spamd send failed: %s", strerror(errno));
  161. (void)fclose(mbox_file);
  162. (void)close(spamd_sock);
  163. return DEFER;
  164. - };
  165. + }
  166. /* now send the file */
  167. /* spamd sometimes accepts connections but doesn't read data off
  168. @@ -304,7 +359,9 @@
  169. (void)fclose(mbox_file);
  170. /* we're done sending, close socket for writing */
  171. - shutdown(spamd_sock,SHUT_WR);
  172. + if (!is_rspamd) {
  173. + shutdown(spamd_sock,SHUT_WR);
  174. + }
  175. /* read spamd response using what's left of the timeout.
  176. */
  177. @@ -328,60 +385,93 @@
  178. /* reading done */
  179. (void)close(spamd_sock);
  180. - /* dig in the spamd output and put the report in a multiline header, if requested */
  181. - if( sscanf(CS spamd_buffer,"SPAMD/%7s 0 EX_OK\r\nContent-length: %*u\r\n\r\n%lf/%lf\r\n%n",
  182. - spamd_version,&spamd_score,&spamd_threshold,&spamd_report_offset) != 3 ) {
  183. -
  184. - /* try to fall back to pre-2.50 spamd output */
  185. - if( sscanf(CS spamd_buffer,"SPAMD/%7s 0 EX_OK\r\nSpam: %*s ; %lf / %lf\r\n\r\n%n",
  186. - spamd_version,&spamd_score,&spamd_threshold,&spamd_report_offset) != 3 ) {
  187. + if (!is_rspamd) {
  188. + /* dig in the spamd output and put the report in a multiline header, if requested */
  189. + if( sscanf(CS spamd_buffer,"SPAMD/%7s 0 EX_OK\r\nContent-length: %*u\r\n\r\n%lf/%lf\r\n%n",
  190. + spamd_version,&spamd_score,&spamd_threshold,&spamd_report_offset) != 3 ) {
  191. +
  192. + /* try to fall back to pre-2.50 spamd output */
  193. + if( sscanf(CS spamd_buffer,"SPAMD/%7s 0 EX_OK\r\nSpam: %*s ; %lf / %lf\r\n\r\n%n",
  194. + spamd_version,&spamd_score,&spamd_threshold,&spamd_report_offset) != 3 ) {
  195. + log_write(0, LOG_MAIN|LOG_PANIC,
  196. + "spam acl condition: cannot parse spamd output");
  197. + return DEFER;
  198. + };
  199. + };
  200. +
  201. + if( spamd_score >= spamd_threshold ) {
  202. + Ustrcpy(spam_action_buffer, "reject");
  203. + }
  204. + else {
  205. + Ustrcpy(spam_action_buffer, "no action");
  206. + }
  207. + }
  208. + else {
  209. + /* rspamd variant of reply */
  210. + int r;
  211. + if( (r = sscanf(CS spamd_buffer,"RSPAMD/%7s 0 EX_OK\r\nMetric: default; %7s %lf / %lf / %lf\r\n%n",
  212. + spamd_version,spamd_short_result,&spamd_score,&spamd_threshold,&spamd_reject_score,&spamd_report_offset)) != 5 ) {
  213. log_write(0, LOG_MAIN|LOG_PANIC,
  214. - "spam acl condition: cannot parse spamd output");
  215. + "spam acl condition: cannot parse spamd output: %d", r);
  216. return DEFER;
  217. };
  218. - };
  219. + /* now parse action */
  220. + p = &spamd_buffer[spamd_report_offset];
  221. +
  222. + if( Ustrncmp(p, "Action: ", sizeof("Action: ") - 1) == 0 ) {
  223. + p += sizeof("Action: ") - 1;
  224. + q = &spam_action_buffer[0];
  225. + while (*p && *p != '\r' && (q - spam_action_buffer) < sizeof(spam_action_buffer) - 1) {
  226. + *q++ = *p++;
  227. + }
  228. + *q = '\0';
  229. + }
  230. + }
  231. /* Create report. Since this is a multiline string,
  232. we must hack it into shape first */
  233. p = &spamd_buffer[spamd_report_offset];
  234. q = spam_report_buffer;
  235. while (*p != '\0') {
  236. - /* skip \r */
  237. - if (*p == '\r') {
  238. - p++;
  239. - continue;
  240. - };
  241. - *q = *p;
  242. - q++;
  243. - if (*p == '\n') {
  244. - /* add an extra space after the newline to ensure
  245. - that it is treated as a header continuation line */
  246. - *q = ' ';
  247. - q++;
  248. - };
  249. - p++;
  250. + /* skip \r */
  251. + if (*p == '\r') {
  252. + p++;
  253. + continue;
  254. + };
  255. + *q = *p;
  256. + q++;
  257. + if (*p == '\n') {
  258. + /* add an extra space after the newline to ensure
  259. + that it is treated as a header continuation line */
  260. + *q = ' ';
  261. + q++;
  262. + };
  263. + p++;
  264. };
  265. /* NULL-terminate */
  266. *q = '\0';
  267. q--;
  268. /* cut off trailing leftovers */
  269. while (*q <= ' ') {
  270. - *q = '\0';
  271. - q--;
  272. + *q = '\0';
  273. + q--;
  274. };
  275. +
  276. + /* common spamd actions */
  277. spam_report = spam_report_buffer;
  278. + spam_action = spam_action_buffer;
  279. /* create spam bar */
  280. spamd_score_char = spamd_score > 0 ? '+' : '-';
  281. j = abs((int)(spamd_score));
  282. i = 0;
  283. if( j != 0 ) {
  284. - while((i < j) && (i <= MAX_SPAM_BAR_CHARS))
  285. - spam_bar_buffer[i++] = spamd_score_char;
  286. + while((i < j) && (i <= MAX_SPAM_BAR_CHARS))
  287. + spam_bar_buffer[i++] = spamd_score_char;
  288. }
  289. else{
  290. - spam_bar_buffer[0] = '/';
  291. - i = 1;
  292. + spam_bar_buffer[0] = '/';
  293. + i = 1;
  294. }
  295. spam_bar_buffer[i] = '\0';
  296. spam_bar = spam_bar_buffer;
  297. @@ -397,12 +487,12 @@
  298. /* compare threshold against score */
  299. if (spamd_score >= spamd_threshold) {
  300. - /* spam as determined by user's threshold */
  301. - spam_rc = OK;
  302. + /* spam as determined by user's threshold */
  303. + spam_rc = OK;
  304. }
  305. else {
  306. - /* not spam */
  307. - spam_rc = FAIL;
  308. + /* not spam */
  309. + spam_rc = FAIL;
  310. };
  311. /* remember user name and "been here" for it unless spamd_socket was expanded */
  312. diff -ru exim-4.70.orig/src/spam.h exim-4.70/src/spam.h
  313. --- exim-4.70.orig/src/spam.h 2016-04-09 13:42:00.235625076 +0200
  314. +++ exim-4.70/src/spam.h 2016-04-09 13:42:37.187633096 +0200
  315. @@ -24,7 +24,8 @@
  316. typedef struct spamd_address_container {
  317. uschar tcp_addr[24];
  318. - unsigned int tcp_port;
  319. + unsigned short int tcp_port;
  320. + int is_rspamd:1;
  321. } spamd_address_container;
  322. #endif