+ report_flag = tmpbuf[ test_byte_order() == LITTLE_MY_ENDIAN ? 1 : 0 ];
+
+ /* read the report, if available */
+ if (report_flag == 1)
+ {
+ /* read report size */
+ if (!recv_len(sock, &kav_reportlen, 4, tmo))
+ return m_errlog_defer_3(scanent, CUS callout_address,
+ US"cannot read report size", sock);
+
+ /* it's possible that avp returns av_buffer[1] == 1 but the
+ reportsize is 0 (!?) */
+ if (kav_reportlen > 0)
+ {
+ /* set up match regex, depends on retcode */
+ if (kav_rc == 3)
+ {
+ if (!kav_re_sus) kav_re_sus = m_pcre_compile(kav_re_sus_str, &errstr);
+ kav_re = kav_re_sus;
+ }
+ else
+ {
+ if (!kav_re_inf) kav_re_inf = m_pcre_compile(kav_re_inf_str, &errstr);
+ kav_re = kav_re_inf;
+ }
+
+ /* read report, linewise. Using size from stream to read amount of data
+ from same stream is safe enough. */
+ /* coverity[tainted_data] */
+ while (kav_reportlen > 0)
+ {
+ if ((bread = recv_line(sock, tmpbuf, sizeof(tmpbuf), tmo)) < 0)
+ break;
+ kav_reportlen -= bread+1;
+
+ /* try matcher on the line, grab substring */
+ if ((malware_name = m_pcre_exec(kav_re, tmpbuf)))
+ break;
+ }
+ }
+ }
+ }
+ else /* no virus found */
+ malware_name = NULL;
+
+ break;
+ }
+#endif
+
+#ifndef DISABLE_MAL_CMDLINE
+ case M_CMDL: /* "cmdline" scanner type ---------------------------------- */
+ {
+ const uschar *cmdline_scanner = scanner_options;
+ const pcre *cmdline_trigger_re;
+ const pcre *cmdline_regex_re;
+ uschar * file_name;
+ uschar * commandline;
+ void (*eximsigchld)(int);
+ void (*eximsigpipe)(int);
+ FILE *scanner_out = NULL;
+ int scanner_fd;
+ FILE *scanner_record = NULL;
+ uschar linebuffer[32767];
+ int rcnt;
+ int trigger = 0;
+ uschar *p;
+
+ if (!cmdline_scanner)
+ return m_errlog_defer(scanent, NULL, errstr);
+
+ /* find scanner output trigger */
+ cmdline_trigger_re = m_pcre_nextinlist(&av_scanner_work, &sep,
+ "missing trigger specification", &errstr);
+ if (!cmdline_trigger_re)
+ return m_errlog_defer(scanent, NULL, errstr);
+
+ /* find scanner name regex */
+ cmdline_regex_re = m_pcre_nextinlist(&av_scanner_work, &sep,
+ "missing virus name regex specification", &errstr);
+ if (!cmdline_regex_re)
+ return m_errlog_defer(scanent, NULL, errstr);
+
+ /* prepare scanner call; despite the naming, file_name holds a directory
+ name which is documented as the value given to %s. */
+
+ file_name = string_copy(eml_filename);
+ p = Ustrrchr(file_name, '/');
+ if (p)
+ *p = '\0';
+ commandline = string_sprintf(CS cmdline_scanner, file_name);
+
+ /* redirect STDERR too */
+ commandline = string_sprintf("%s 2>&1", commandline);
+
+ DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s scan [%s]\n",
+ scanner_name, commandline);
+
+ /* store exims signal handlers */
+ eximsigchld = signal(SIGCHLD,SIG_DFL);
+ eximsigpipe = signal(SIGPIPE,SIG_DFL);
+
+ if (!(scanner_out = popen(CS commandline,"r")))
+ {
+ int err = errno;
+ signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe);
+ return m_errlog_defer(scanent, NULL,
+ string_sprintf("call (%s) failed: %s.", commandline, strerror(err)));