1
/* $Cambridge: exim/exim-src/src/malware.c,v 1.11 2005/07/01 10:49:02 ph10 Exp $ */
3
/*************************************************
4
* Exim - an Internet mail transport agent *
5
*************************************************/
7
/* Copyright (c) Tom Kistner <tom@duncanthrax.net> 2003-???? */
10
/* Code for calling virus (malware) scanners. Called from acl.c. */
13
#ifdef WITH_CONTENT_SCAN
15
/* declaration of private routines */
16
int mksd_scan_packed(int sock);
18
/* SHUT_WR seems to be undefined on Unixware? */
23
#define DRWEBD_SCAN_CMD (1) /* scan file, buffer or diskfile */
24
#define DRWEBD_RETURN_VIRUSES (1<<0) /* ask daemon return to us viruses names from report */
25
#define DRWEBD_IS_MAIL (1<<19) /* say to daemon that format is "archive MAIL" */
27
#define DERR_READ_ERR (1<<0) /* read error */
28
#define DERR_NOMEMORY (1<<2) /* no memory */
29
#define DERR_TIMEOUT (1<<9) /* scan timeout has run out */
30
#define DERR_BAD_CALL (1<<15) /* wrong command */
32
/* Routine to check whether a system is big- or litte-endian.
33
Ripped from http://www.faqs.org/faqs/graphics/fileformats-faq/part4/section-7.html
34
Needed for proper kavdaemon implementation. Sigh. */
35
#define BIG_MY_ENDIAN 0
36
#define LITTLE_MY_ENDIAN 1
37
int test_byte_order(void);
38
int test_byte_order() {
39
short int word = 0x0001;
40
char *byte = (char *) &word;
41
return(byte[0] ? LITTLE_MY_ENDIAN : BIG_MY_ENDIAN);
44
uschar malware_name_buffer[256];
47
int malware(uschar **listptr) {
49
uschar *list = *listptr;
50
uschar *av_scanner_work = av_scanner;
52
uschar scanner_name_buffer[16];
53
uschar *malware_regex;
54
uschar malware_regex_buffer[64];
55
uschar malware_regex_default[] = ".+";
56
unsigned long mbox_size;
62
/* make sure the eml mbox file is spooled up */
63
mbox_file = spool_mbox(&mbox_size);
64
if (mbox_file == NULL) {
65
/* error while spooling */
66
log_write(0, LOG_MAIN|LOG_PANIC,
67
"malware acl condition: error while creating mbox spool file");
70
/* none of our current scanners need the mbox
71
file as a stream, so we can close it right away */
72
(void)fclose(mbox_file);
74
/* extract the malware regex to match against from the option list */
75
if ((malware_regex = string_nextinlist(&list, &sep,
77
sizeof(malware_regex_buffer))) != NULL) {
79
/* parse 1st option */
80
if ( (strcmpic(malware_regex,US"false") == 0) ||
81
(Ustrcmp(malware_regex,"0") == 0) ) {
82
/* explicitly no matching */
86
/* special cases (match anything except empty) */
87
if ( (strcmpic(malware_regex,US"true") == 0) ||
88
(Ustrcmp(malware_regex,"*") == 0) ||
89
(Ustrcmp(malware_regex,"1") == 0) ) {
90
malware_regex = malware_regex_default;
94
/* empty means "don't match anything" */
98
/* Reset sep that is set by previous string_nextinlist() call */
101
/* compile the regex, see if it works */
102
re = pcre_compile(CS malware_regex, PCRE_COPT, (const char **)&rerror, &roffset, NULL);
104
log_write(0, LOG_MAIN|LOG_PANIC,
105
"malware acl condition: regular expression error in '%s': %s at offset %d", malware_regex, rerror, roffset);
109
/* if av_scanner starts with a dollar, expand it first */
110
if (*av_scanner == '$') {
111
av_scanner_work = expand_string(av_scanner);
112
if (av_scanner_work == NULL) {
113
log_write(0, LOG_MAIN|LOG_PANIC,
114
"malware acl condition: av_scanner starts with $, but expansion failed: %s", expand_string_message);
118
debug_printf("Expanded av_scanner global: %s\n", av_scanner_work);
119
/* disable result caching in this case */
125
/* Do not scan twice. */
126
if (malware_ok == 0) {
128
/* find the scanner type from the av_scanner option */
129
if ((scanner_name = string_nextinlist(&av_scanner_work, &sep,
131
sizeof(scanner_name_buffer))) == NULL) {
132
/* no scanner given */
133
log_write(0, LOG_MAIN|LOG_PANIC,
134
"malware acl condition: av_scanner configuration variable is empty");
138
/* "drweb" scanner type ----------------------------------------------- */
139
/* v0.1 - added support for tcp sockets */
140
/* v0.0 - initial release -- support for unix sockets */
141
if (strcmpic(scanner_name,US"drweb") == 0) {
142
uschar *drweb_options;
143
uschar drweb_options_buffer[1024];
144
uschar drweb_options_default[] = "/usr/local/drweb/run/drwebd.sock";
145
struct sockaddr_un server;
146
int sock, result, ovector[30];
147
unsigned int port, fsize;
148
uschar tmpbuf[1024], *drweb_fbuf;
149
uschar scanrequest[1024];
150
uschar drweb_match_string[128];
151
int drweb_rc, drweb_cmd, drweb_flags = 0x0000, drweb_fd,
152
drweb_vnum, drweb_slen, drweb_fin = 0x0000;
154
uschar hostname[256];
159
if ((drweb_options = string_nextinlist(&av_scanner_work, &sep,
160
drweb_options_buffer, sizeof(drweb_options_buffer))) == NULL) {
161
/* no options supplied, use default options */
162
drweb_options = drweb_options_default;
165
if (*drweb_options != '/') {
167
/* extract host and port part */
168
if( sscanf(CS drweb_options, "%s %u", hostname, &port) != 2 ) {
169
log_write(0, LOG_MAIN|LOG_PANIC,
170
"malware acl condition: drweb: invalid socket '%s'", drweb_options);
174
/* Lookup the host */
175
if((he = gethostbyname(CS hostname)) == 0) {
176
log_write(0, LOG_MAIN|LOG_PANIC,
177
"malware acl condition: drweb: failed to lookup host '%s'", hostname);
181
in = *(struct in_addr *) he->h_addr_list[0];
183
/* Open the drwebd TCP socket */
184
if ( (sock = ip_socket(SOCK_STREAM, AF_INET)) < 0) {
185
log_write(0, LOG_MAIN|LOG_PANIC,
186
"malware acl condition: drweb: unable to acquire socket (%s)",
191
if (ip_connect(sock, AF_INET, (uschar*)inet_ntoa(in), port, 5) < 0) {
193
log_write(0, LOG_MAIN|LOG_PANIC,
194
"malware acl condition: drweb: connection to %s, port %u failed (%s)",
195
inet_ntoa(in), port, strerror(errno));
199
/* prepare variables */
200
drweb_cmd = htonl(DRWEBD_SCAN_CMD);
201
drweb_flags = htonl(DRWEBD_RETURN_VIRUSES | DRWEBD_IS_MAIL);
202
snprintf(CS scanrequest, 1024,CS"%s/scan/%s/%s.eml",
203
spool_directory, message_id, message_id);
206
drweb_fd = open(CS scanrequest, O_RDONLY);
207
if (drweb_fd == -1) {
209
log_write(0, LOG_MAIN|LOG_PANIC,
210
"malware acl condition: drweb: can't open spool file %s: %s",
211
scanrequest, strerror(errno));
214
fsize = lseek(drweb_fd, 0, SEEK_END);
217
(void)close(drweb_fd);
218
log_write(0, LOG_MAIN|LOG_PANIC,
219
"malware acl condition: drweb: can't seek spool file %s: %s",
220
scanrequest, strerror(errno));
223
drweb_slen = htonl(fsize);
224
lseek(drweb_fd, 0, SEEK_SET);
226
/* send scan request */
227
if ((send(sock, &drweb_cmd, sizeof(drweb_cmd), 0) < 0) ||
228
(send(sock, &drweb_flags, sizeof(drweb_flags), 0) < 0) ||
229
(send(sock, &drweb_fin, sizeof(drweb_fin), 0) < 0) ||
230
(send(sock, &drweb_slen, sizeof(drweb_slen), 0) < 0)) {
232
(void)close(drweb_fd);
233
log_write(0, LOG_MAIN|LOG_PANIC,
234
"malware acl condition: drweb: unable to send commands to socket (%s)", drweb_options);
238
drweb_fbuf = (uschar *) malloc (fsize);
241
(void)close(drweb_fd);
242
log_write(0, LOG_MAIN|LOG_PANIC,
243
"malware acl condition: drweb: unable to allocate memory %u for file (%s)",
248
result = read (drweb_fd, drweb_fbuf, fsize);
251
(void)close(drweb_fd);
253
log_write(0, LOG_MAIN|LOG_PANIC,
254
"malware acl condition: drweb: can't read spool file %s: %s",
255
scanrequest, strerror(errno));
258
(void)close(drweb_fd);
260
/* send file body to socket */
261
if (send(sock, drweb_fbuf, fsize, 0) < 0) {
264
log_write(0, LOG_MAIN|LOG_PANIC,
265
"malware acl condition: drweb: unable to send file body to socket (%s)", drweb_options);
268
(void)close(drweb_fd);
271
/* open the drwebd UNIX socket */
272
sock = socket(AF_UNIX, SOCK_STREAM, 0);
274
log_write(0, LOG_MAIN|LOG_PANIC,
275
"malware acl condition: drweb: can't open UNIX socket");
278
server.sun_family = AF_UNIX;
279
Ustrcpy(server.sun_path, drweb_options);
280
if (connect(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) < 0) {
282
log_write(0, LOG_MAIN|LOG_PANIC,
283
"malware acl condition: drweb: unable to connect to socket (%s). errno=%d", drweb_options, errno);
287
/* prepare variables */
288
drweb_cmd = htonl(DRWEBD_SCAN_CMD);
289
drweb_flags = htonl(DRWEBD_RETURN_VIRUSES | DRWEBD_IS_MAIL);
290
snprintf(CS scanrequest, 1024,CS"%s/scan/%s/%s.eml", spool_directory, message_id, message_id);
291
drweb_slen = htonl(Ustrlen(scanrequest));
293
/* send scan request */
294
if ((send(sock, &drweb_cmd, sizeof(drweb_cmd), 0) < 0) ||
295
(send(sock, &drweb_flags, sizeof(drweb_flags), 0) < 0) ||
296
(send(sock, &drweb_slen, sizeof(drweb_slen), 0) < 0) ||
297
(send(sock, scanrequest, Ustrlen(scanrequest), 0) < 0) ||
298
(send(sock, &drweb_fin, sizeof(drweb_fin), 0) < 0)) {
300
log_write(0, LOG_MAIN|LOG_PANIC,
301
"malware acl condition: drweb: unable to send commands to socket (%s)", drweb_options);
306
/* wait for result */
307
if ((bread = recv(sock, &drweb_rc, sizeof(drweb_rc), 0) != sizeof(drweb_rc))) {
309
log_write(0, LOG_MAIN|LOG_PANIC,
310
"malware acl condition: drweb: unable to read return code");
313
drweb_rc = ntohl(drweb_rc);
315
if ((bread = recv(sock, &drweb_vnum, sizeof(drweb_vnum), 0) != sizeof(drweb_vnum))) {
317
log_write(0, LOG_MAIN|LOG_PANIC,
318
"malware acl condition: drweb: unable to read the number of viruses");
321
drweb_vnum = ntohl(drweb_vnum);
323
/* "virus(es) found" if virus number is > 0 */
327
uschar pre_malware_nb[256];
329
malware_name = malware_name_buffer;
331
/* setup default virus name */
332
Ustrcpy(malware_name_buffer,"unknown");
334
/* read and concatenate virus names into one string */
335
for (i=0;i<drweb_vnum;i++)
337
/* read the size of report */
338
if ((bread = recv(sock, &drweb_slen, sizeof(drweb_slen), 0) != sizeof(drweb_slen))) {
340
log_write(0, LOG_MAIN|LOG_PANIC,
341
"malware acl condition: drweb: cannot read report size");
344
drweb_slen = ntohl(drweb_slen);
346
/* read report body */
347
if ((bread = recv(sock, tmpbuf, drweb_slen, 0)) != drweb_slen) {
349
log_write(0, LOG_MAIN|LOG_PANIC,
350
"malware acl condition: drweb: cannot read report string");
353
tmpbuf[drweb_slen] = '\0';
355
/* set up match regex, depends on retcode */
356
Ustrcpy(drweb_match_string, "infected\\swith\\s*(.+?)$");
358
drweb_re = pcre_compile( CS drweb_match_string,
360
(const char **)&rerror,
364
/* try matcher on the line, grab substring */
365
result = pcre_exec(drweb_re, NULL, CS tmpbuf, Ustrlen(tmpbuf), 0, 0, ovector, 30);
367
pcre_copy_substring(CS tmpbuf, ovector, result, 1, CS pre_malware_nb, 255);
369
/* the first name we just copy to malware_name */
371
Ustrcpy(CS malware_name_buffer, CS pre_malware_nb);
373
/* concatenate each new virus name to previous */
374
int slen = Ustrlen(malware_name_buffer);
375
if (slen < (slen+Ustrlen(pre_malware_nb))) {
376
Ustrcat(malware_name_buffer, "/");
377
Ustrcat(malware_name_buffer, pre_malware_nb);
383
char *drweb_s = NULL;
385
if (drweb_rc & DERR_READ_ERR) drweb_s = "read error";
386
if (drweb_rc & DERR_NOMEMORY) drweb_s = "no memory";
387
if (drweb_rc & DERR_TIMEOUT) drweb_s = "timeout";
388
if (drweb_rc & DERR_BAD_CALL) drweb_s = "wrong command";
389
/* retcodes DERR_SYMLINK, DERR_NO_REGFILE, DERR_SKIPPED.
390
* DERR_TOO_BIG, DERR_TOO_COMPRESSED, DERR_SPAM,
391
* DERR_CRC_ERROR, DERR_READSOCKET, DERR_WRITE_ERR
392
* and others are ignored */
394
log_write(0, LOG_MAIN|LOG_PANIC,
395
"malware acl condition: drweb: drweb daemon retcode 0x%x (%s)", drweb_rc, drweb_s);
404
/* ----------------------------------------------------------------------- */
405
else if (strcmpic(scanner_name,US"aveserver") == 0) {
407
uschar kav_options_buffer[1024];
408
uschar kav_options_default[] = "/var/run/aveserver";
410
struct sockaddr_un server;
414
if ((kav_options = string_nextinlist(&av_scanner_work, &sep,
416
sizeof(kav_options_buffer))) == NULL) {
417
/* no options supplied, use default options */
418
kav_options = kav_options_default;
421
/* open the aveserver socket */
422
sock = socket(AF_UNIX, SOCK_STREAM, 0);
424
log_write(0, LOG_MAIN|LOG_PANIC,
425
"malware acl condition: can't open UNIX socket.");
428
server.sun_family = AF_UNIX;
429
Ustrcpy(server.sun_path, kav_options);
430
if (connect(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) < 0) {
432
log_write(0, LOG_MAIN|LOG_PANIC,
433
"malware acl condition: unable to connect to aveserver UNIX socket (%s). errno=%d", kav_options, errno);
437
/* read aveserver's greeting and see if it is ready (2xx greeting) */
438
recv_line(sock, buf, 32768);
441
/* aveserver is having problems */
443
log_write(0, LOG_MAIN|LOG_PANIC,
444
"malware acl condition: aveserver is unavailable (Responded: %s).", ((buf[0] != 0) ? buf : (uschar *)"nothing") );
448
/* prepare our command */
449
snprintf(CS buf, 32768, "SCAN bPQRSTUW %s/scan/%s/%s.eml\r\n", spool_directory, message_id, message_id);
452
if (send(sock, buf, Ustrlen(buf), 0) < 0) {
454
log_write(0, LOG_MAIN|LOG_PANIC,
455
"malware acl condition: unable to write to aveserver UNIX socket (%s)", kav_options);
461
/* read response lines, find malware name and final response */
462
while (recv_line(sock, buf, 32768) > 0) {
463
debug_printf("aveserver: %s\n", buf);
466
} else if (buf[0] == '5') {
467
/* aveserver is having problems */
468
log_write(0, LOG_MAIN|LOG_PANIC,
469
"malware acl condition: unable to scan file %s/scan/%s/%s.eml (Responded: %s).",
470
spool_directory, message_id, message_id, buf);
473
} else if (Ustrncmp(buf,"322",3) == 0) {
474
uschar *p = Ustrchr(&buf[4],' ');
476
Ustrcpy(malware_name_buffer,&buf[4]);
477
malware_name = malware_name_buffer;
481
/* prepare our command */
482
snprintf(CS buf, 32768, "quit\r\n");
485
if (send(sock, buf, Ustrlen(buf), 0) < 0) {
487
log_write(0, LOG_MAIN|LOG_PANIC,
488
"malware acl condition: unable to write to aveserver UNIX socket (%s)", kav_options);
492
/* read aveserver's greeting and see if it is ready (2xx greeting) */
493
recv_line(sock, buf, 32768);
496
/* aveserver is having problems */
498
log_write(0, LOG_MAIN|LOG_PANIC,
499
"malware acl condition: unable to quit aveserver dialogue (Responded: %s).", ((buf[0] != 0) ? buf : (uschar *)"nothing") );
505
if (result == DEFER) return DEFER;
507
/* "fsecure" scanner type ------------------------------------------------- */
508
else if (strcmpic(scanner_name,US"fsecure") == 0) {
509
uschar *fsecure_options;
510
uschar fsecure_options_buffer[1024];
511
uschar fsecure_options_default[] = "/var/run/.fsav";
512
struct sockaddr_un server;
513
int sock, i, j, bread = 0;
514
uschar file_name[1024];
515
uschar av_buffer[1024];
517
static uschar *cmdoptions[] = { US"CONFIGURE\tARCHIVE\t1\n",
518
US"CONFIGURE\tTIMEOUT\t0\n",
519
US"CONFIGURE\tMAXARCH\t5\n",
520
US"CONFIGURE\tMIME\t1\n" };
523
if ((fsecure_options = string_nextinlist(&av_scanner_work, &sep,
524
fsecure_options_buffer,
525
sizeof(fsecure_options_buffer))) == NULL) {
526
/* no options supplied, use default options */
527
fsecure_options = fsecure_options_default;
530
/* open the fsecure socket */
531
sock = socket(AF_UNIX, SOCK_STREAM, 0);
533
log_write(0, LOG_MAIN|LOG_PANIC,
534
"malware acl condition: unable to open fsecure socket %s (%s)",
535
fsecure_options, strerror(errno));
538
server.sun_family = AF_UNIX;
539
Ustrcpy(server.sun_path, fsecure_options);
540
if (connect(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) < 0) {
542
log_write(0, LOG_MAIN|LOG_PANIC,
543
"malware acl condition: unable to connect to fsecure socket %s (%s)",
544
fsecure_options, strerror(errno));
549
memset(av_buffer, 0, sizeof(av_buffer));
550
for (i=0; i != 4; i++) {
551
/* debug_printf("send option \"%s\"",cmdoptions[i]); */
552
if (write(sock, cmdoptions[i], Ustrlen(cmdoptions[i])) < 0) {
554
log_write(0, LOG_MAIN|LOG_PANIC,
555
"malware acl condition: unable to write fsecure option %d to %s (%s)",
556
i, fsecure_options, strerror(errno));
560
bread = read(sock, av_buffer, sizeof(av_buffer));
561
if (bread >0) av_buffer[bread]='\0';
564
log_write(0, LOG_MAIN|LOG_PANIC,
565
"malware acl condition: unable to read fsecure answer %d (%s)", i, strerror(errno));
568
for (j=0;j<bread;j++) if((av_buffer[j]=='\r')||(av_buffer[j]=='\n')) av_buffer[j] ='@';
569
/* debug_printf("read answer %d read=%d \"%s\"\n", i, bread, av_buffer ); */
570
/* while (Ustrstr(av_buffer, "OK\tServer configured.@") == NULL); */
573
/* pass the mailfile to fsecure */
574
snprintf(CS file_name,1024,"SCAN\t%s/scan/%s/%s.eml\n", spool_directory, message_id, message_id);
575
/* debug_printf("send scan %s",file_name); */
576
if (write(sock, file_name, Ustrlen(file_name)) < 0) {
578
log_write(0, LOG_MAIN|LOG_PANIC,
579
"malware acl condition: unable to write fsecure scan to %s (%s)",
580
fsecure_options, strerror(errno));
585
/* todo also SUSPICION\t */
586
fs_inf = pcre_compile("\\S{0,5}INFECTED\\t[^\\t]*\\t([^\\t]+)\\t\\S*$", PCRE_COPT, (const char **)&rerror, &roffset, NULL);
588
/* read report, linewise */
592
memset(av_buffer, 0, sizeof(av_buffer));
594
bread=read(sock, &av_buffer[i], 1);
597
log_write(0, LOG_MAIN|LOG_PANIC,
598
"malware acl condition: unable to read fsecure result (%s)", strerror(errno));
603
while ((i < sizeof(av_buffer)-1 ) && (av_buffer[i-1] != '\n'));
604
av_buffer[i-1] = '\0';
605
/* debug_printf("got line \"%s\"\n",av_buffer); */
607
/* Really search for virus again? */
608
if (malware_name == NULL) {
609
/* try matcher on the line, grab substring */
610
i = pcre_exec(fs_inf, NULL, CS av_buffer, Ustrlen(av_buffer), 0, 0, ovector, 30);
613
pcre_copy_substring(CS av_buffer, ovector, i, 1, CS malware_name_buffer, 255);
614
malware_name = malware_name_buffer;
618
while (Ustrstr(av_buffer, "OK\tScan ok.") == NULL);
621
/* ----------------------------------------------------------------------- */
623
/* "kavdaemon" scanner type ------------------------------------------------ */
624
else if (strcmpic(scanner_name,US"kavdaemon") == 0) {
626
uschar kav_options_buffer[1024];
627
uschar kav_options_default[] = "/var/run/AvpCtl";
628
struct sockaddr_un server;
632
uschar scanrequest[1024];
633
uschar kav_match_string[128];
635
unsigned long kav_reportlen, bread;
638
if ((kav_options = string_nextinlist(&av_scanner_work, &sep,
640
sizeof(kav_options_buffer))) == NULL) {
641
/* no options supplied, use default options */
642
kav_options = kav_options_default;
645
/* open the kavdaemon socket */
646
sock = socket(AF_UNIX, SOCK_STREAM, 0);
648
log_write(0, LOG_MAIN|LOG_PANIC,
649
"malware acl condition: can't open UNIX socket.");
652
server.sun_family = AF_UNIX;
653
Ustrcpy(server.sun_path, kav_options);
654
if (connect(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) < 0) {
656
log_write(0, LOG_MAIN|LOG_PANIC,
657
"malware acl condition: unable to connect to kavdaemon UNIX socket (%s). errno=%d", kav_options, errno);
661
/* get current date and time, build scan request */
663
strftime(CS tmpbuf, sizeof(tmpbuf), "<0>%d %b %H:%M:%S:%%s/scan/%%s", localtime(&t));
664
snprintf(CS scanrequest, 1024,CS tmpbuf, spool_directory, message_id);
666
/* send scan request */
667
if (send(sock, scanrequest, Ustrlen(scanrequest)+1, 0) < 0) {
669
log_write(0, LOG_MAIN|LOG_PANIC,
670
"malware acl condition: unable to write to kavdaemon UNIX socket (%s)", kav_options);
674
/* wait for result */
675
if ((bread = recv(sock, tmpbuf, 2, 0) != 2)) {
677
log_write(0, LOG_MAIN|LOG_PANIC,
678
"malware acl condition: unable to read 2 bytes from kavdaemon socket.");
682
/* get errorcode from one nibble */
683
if (test_byte_order() == LITTLE_MY_ENDIAN) {
684
kav_rc = tmpbuf[0] & 0x0F;
687
kav_rc = tmpbuf[1] & 0x0F;
690
/* improper kavdaemon configuration */
691
if ( (kav_rc == 5) || (kav_rc == 6) ) {
693
log_write(0, LOG_MAIN|LOG_PANIC,
694
"malware acl condition: please reconfigure kavdaemon to NOT disinfect or remove infected files.");
700
log_write(0, LOG_MAIN|LOG_PANIC,
701
"malware acl condition: kavdaemon reported 'scanning not completed' (code 1).");
707
log_write(0, LOG_MAIN|LOG_PANIC,
708
"malware acl condition: kavdaemon reported 'kavdaemon damaged' (code 7).");
712
/* code 8 is not handled, since it is ambigous. It appears mostly on
713
bounces where part of a file has been cut off */
715
/* "virus found" return codes (2-4) */
716
if ((kav_rc > 1) && (kav_rc < 5)) {
719
/* setup default virus name */
720
Ustrcpy(malware_name_buffer,"unknown");
721
malware_name = malware_name_buffer;
723
if (test_byte_order() == LITTLE_MY_ENDIAN) {
724
report_flag = tmpbuf[1];
727
report_flag = tmpbuf[0];
730
/* read the report, if available */
731
if( report_flag == 1 ) {
732
/* read report size */
733
if ((bread = recv(sock, &kav_reportlen, 4, 0)) != 4) {
735
log_write(0, LOG_MAIN|LOG_PANIC,
736
"malware acl condition: cannot read report size from kavdaemon");
740
/* it's possible that avp returns av_buffer[1] == 1 but the
741
reportsize is 0 (!?) */
742
if (kav_reportlen > 0) {
743
/* set up match regex, depends on retcode */
745
Ustrcpy(kav_match_string, "suspicion:\\s*(.+?)\\s*$");
747
Ustrcpy(kav_match_string, "infected:\\s*(.+?)\\s*$");
749
kav_re = pcre_compile( CS kav_match_string,
751
(const char **)&rerror,
755
/* read report, linewise */
756
while (kav_reportlen > 0) {
761
while ( recv(sock, &tmpbuf[bread], 1, 0) == 1 ) {
763
if ( (tmpbuf[bread] == '\n') || (bread > 1021) ) break;
767
tmpbuf[bread] = '\0';
769
/* try matcher on the line, grab substring */
770
result = pcre_exec(kav_re, NULL, CS tmpbuf, Ustrlen(tmpbuf), 0, 0, ovector, 30);
772
pcre_copy_substring(CS tmpbuf, ovector, result, 1, CS malware_name_buffer, 255);
786
/* ----------------------------------------------------------------------- */
789
/* "cmdline" scanner type ------------------------------------------------ */
790
else if (strcmpic(scanner_name,US"cmdline") == 0) {
791
uschar *cmdline_scanner;
792
uschar cmdline_scanner_buffer[1024];
793
uschar *cmdline_trigger;
794
uschar cmdline_trigger_buffer[1024];
795
const pcre *cmdline_trigger_re;
796
uschar *cmdline_regex;
797
uschar cmdline_regex_buffer[1024];
798
const pcre *cmdline_regex_re;
799
uschar file_name[1024];
800
uschar commandline[1024];
801
void (*eximsigchld)(int);
802
void (*eximsigpipe)(int);
803
FILE *scanner_out = NULL;
804
FILE *scanner_record = NULL;
805
uschar linebuffer[32767];
810
/* find scanner command line */
811
if ((cmdline_scanner = string_nextinlist(&av_scanner_work, &sep,
812
cmdline_scanner_buffer,
813
sizeof(cmdline_scanner_buffer))) == NULL) {
814
/* no command line supplied */
815
log_write(0, LOG_MAIN|LOG_PANIC,
816
"malware acl condition: missing commandline specification for cmdline scanner type.");
820
/* find scanner output trigger */
821
if ((cmdline_trigger = string_nextinlist(&av_scanner_work, &sep,
822
cmdline_trigger_buffer,
823
sizeof(cmdline_trigger_buffer))) == NULL) {
824
/* no trigger regex supplied */
825
log_write(0, LOG_MAIN|LOG_PANIC,
826
"malware acl condition: missing trigger specification for cmdline scanner type.");
830
/* precompile trigger regex */
831
cmdline_trigger_re = pcre_compile(CS cmdline_trigger, PCRE_COPT, (const char **)&rerror, &roffset, NULL);
832
if (cmdline_trigger_re == NULL) {
833
log_write(0, LOG_MAIN|LOG_PANIC,
834
"malware acl condition: regular expression error in '%s': %s at offset %d", cmdline_trigger_re, rerror, roffset);
838
/* find scanner name regex */
839
if ((cmdline_regex = string_nextinlist(&av_scanner_work, &sep,
840
cmdline_regex_buffer,
841
sizeof(cmdline_regex_buffer))) == NULL) {
842
/* no name regex supplied */
843
log_write(0, LOG_MAIN|LOG_PANIC,
844
"malware acl condition: missing virus name regex specification for cmdline scanner type.");
848
/* precompile name regex */
849
cmdline_regex_re = pcre_compile(CS cmdline_regex, PCRE_COPT, (const char **)&rerror, &roffset, NULL);
850
if (cmdline_regex_re == NULL) {
851
log_write(0, LOG_MAIN|LOG_PANIC,
852
"malware acl condition: regular expression error in '%s': %s at offset %d", cmdline_regex_re, rerror, roffset);
856
/* prepare scanner call */
857
snprintf(CS file_name,1024,"%s/scan/%s", spool_directory, message_id);
858
snprintf(CS commandline,1024, CS cmdline_scanner,file_name);
859
/* redirect STDERR too */
860
Ustrcat(commandline," 2>&1");
862
/* store exims signal handlers */
863
eximsigchld = signal(SIGCHLD,SIG_DFL);
864
eximsigpipe = signal(SIGPIPE,SIG_DFL);
866
scanner_out = popen(CS commandline,"r");
867
if (scanner_out == NULL) {
868
log_write(0, LOG_MAIN|LOG_PANIC,
869
"malware acl condition: calling cmdline scanner (%s) failed: %s.", commandline, strerror(errno));
870
signal(SIGCHLD,eximsigchld);
871
signal(SIGPIPE,eximsigpipe);
875
snprintf(CS file_name,1024,"%s/scan/%s/%s_scanner_output", spool_directory, message_id, message_id);
876
scanner_record = fopen(CS file_name,"wb");
878
if (scanner_record == NULL) {
879
log_write(0, LOG_MAIN|LOG_PANIC,
880
"malware acl condition: opening scanner output file (%s) failed: %s.", file_name, strerror(errno));
882
signal(SIGCHLD,eximsigchld);
883
signal(SIGPIPE,eximsigpipe);
887
/* look for trigger while recording output */
888
while(fgets(CS linebuffer,32767,scanner_out) != NULL) {
889
if ( Ustrlen(linebuffer) > fwrite(linebuffer, 1, Ustrlen(linebuffer), scanner_record) ) {
891
log_write(0, LOG_MAIN|LOG_PANIC,
892
"malware acl condition: short write on scanner output file (%s).", file_name);
894
signal(SIGCHLD,eximsigchld);
895
signal(SIGPIPE,eximsigpipe);
898
/* try trigger match */
899
if (!trigger && regex_match_and_setup(cmdline_trigger_re, linebuffer, 0, -1))
903
(void)fclose(scanner_record);
905
signal(SIGCHLD,eximsigchld);
906
signal(SIGPIPE,eximsigpipe);
909
/* setup default virus name */
910
Ustrcpy(malware_name_buffer,"unknown");
911
malware_name = malware_name_buffer;
913
/* re-open the scanner output file, look for name match */
914
scanner_record = fopen(CS file_name,"rb");
915
while(fgets(CS linebuffer,32767,scanner_record) != NULL) {
917
result = pcre_exec(cmdline_regex_re, NULL, CS linebuffer, Ustrlen(linebuffer), 0, 0, ovector, 30);
919
pcre_copy_substring(CS linebuffer, ovector, result, 1, CS malware_name_buffer, 255);
922
(void)fclose(scanner_record);
929
/* ----------------------------------------------------------------------- */
932
/* "sophie" scanner type ------------------------------------------------- */
933
else if (strcmpic(scanner_name,US"sophie") == 0) {
934
uschar *sophie_options;
935
uschar sophie_options_buffer[1024];
936
uschar sophie_options_default[] = "/var/run/sophie";
938
struct sockaddr_un server;
940
uschar file_name[1024];
941
uschar av_buffer[1024];
943
if ((sophie_options = string_nextinlist(&av_scanner_work, &sep,
944
sophie_options_buffer,
945
sizeof(sophie_options_buffer))) == NULL) {
946
/* no options supplied, use default options */
947
sophie_options = sophie_options_default;
950
/* open the sophie socket */
951
sock = socket(AF_UNIX, SOCK_STREAM, 0);
953
log_write(0, LOG_MAIN|LOG_PANIC,
954
"malware acl condition: can't open UNIX socket.");
957
server.sun_family = AF_UNIX;
958
Ustrcpy(server.sun_path, sophie_options);
959
if (connect(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) < 0) {
961
log_write(0, LOG_MAIN|LOG_PANIC,
962
"malware acl condition: unable to connect to sophie UNIX socket (%s). errno=%d", sophie_options, errno);
966
/* pass the scan directory to sophie */
967
snprintf(CS file_name,1024,"%s/scan/%s", spool_directory, message_id);
968
if (write(sock, file_name, Ustrlen(file_name)) < 0) {
970
log_write(0, LOG_MAIN|LOG_PANIC,
971
"malware acl condition: unable to write to sophie UNIX socket (%s)", sophie_options);
975
(void)write(sock, "\n", 1);
977
/* wait for result */
978
memset(av_buffer, 0, sizeof(av_buffer));
979
if ((!(bread = read(sock, av_buffer, sizeof(av_buffer))) > 0)) {
981
log_write(0, LOG_MAIN|LOG_PANIC,
982
"malware acl condition: unable to read from sophie UNIX socket (%s)", sophie_options);
989
if (av_buffer[0] == '1') {
990
if (Ustrchr(av_buffer, '\n')) *Ustrchr(av_buffer, '\n') = '\0';
991
Ustrcpy(malware_name_buffer,&av_buffer[2]);
992
malware_name = malware_name_buffer;
994
else if (!strncmp(CS av_buffer, "-1", 2)) {
995
log_write(0, LOG_MAIN|LOG_PANIC,
996
"malware acl condition: malware acl condition: sophie reported error");
1000
/* all ok, no virus */
1001
malware_name = NULL;
1004
/* ----------------------------------------------------------------------- */
1007
/* "clamd" scanner type ------------------------------------------------- */
1008
/* This code was contributed by David Saez */
1009
else if (strcmpic(scanner_name,US"clamd") == 0) {
1010
uschar *clamd_options;
1011
uschar clamd_options_buffer[1024];
1012
uschar clamd_options_default[] = "/tmp/clamd";
1014
struct sockaddr_un server;
1017
uschar file_name[1024];
1018
uschar av_buffer[1024];
1019
uschar hostname[256];
1022
uschar *clamd_options2;
1023
uschar clamd_options2_buffer[1024];
1024
uschar clamd_options2_default[] = "";
1025
uschar av_buffer2[1024];
1026
uschar *clamav_fbuf;
1027
uschar scanrequest[1024];
1028
int sockData, clam_fd, result;
1031
if ((clamd_options = string_nextinlist(&av_scanner_work, &sep,
1032
clamd_options_buffer,
1033
sizeof(clamd_options_buffer))) == NULL) {
1034
/* no options supplied, use default options */
1035
clamd_options = clamd_options_default;
1037
if ((clamd_options2 = string_nextinlist(&av_scanner_work, &sep,
1038
clamd_options2_buffer,
1039
sizeof(clamd_options2_buffer))) == NULL) {
1040
clamd_options2 = clamd_options2_default;
1043
/* socket does not start with '/' -> network socket */
1044
if (*clamd_options != '/') {
1046
/* extract host and port part */
1047
if( sscanf(CS clamd_options, "%s %u", hostname, &port) != 2 ) {
1048
log_write(0, LOG_MAIN|LOG_PANIC,
1049
"malware acl condition: clamd: invalid socket '%s'", clamd_options);
1053
/* Lookup the host */
1054
if((he = gethostbyname(CS hostname)) == 0) {
1055
log_write(0, LOG_MAIN|LOG_PANIC,
1056
"malware acl condition: clamd: failed to lookup host '%s'", hostname);
1060
in = *(struct in_addr *) he->h_addr_list[0];
1062
/* Open the ClamAV Socket */
1063
if ( (sock = ip_socket(SOCK_STREAM, AF_INET)) < 0) {
1064
log_write(0, LOG_MAIN|LOG_PANIC,
1065
"malware acl condition: clamd: unable to acquire socket (%s)",
1070
if (ip_connect(sock, AF_INET, (uschar*)inet_ntoa(in), port, 5) < 0) {
1072
log_write(0, LOG_MAIN|LOG_PANIC,
1073
"malware acl condition: clamd: connection to %s, port %u failed (%s)",
1074
inet_ntoa(in), port, strerror(errno));
1078
if (strcmpic(clamd_options2,US"local") == 0) {
1080
/* Pass the string to ClamAV (7 = "SCAN \n" + \0) */
1082
snprintf(CS file_name,1024,"SCAN %s/scan/%s\n", spool_directory, message_id);
1084
if (send(sock, file_name, Ustrlen(file_name), 0) < 0) {
1086
log_write(0, LOG_MAIN|LOG_PANIC,"malware acl condition: clamd: unable to write to socket (%s)",
1092
/* Pass the string to ClamAV (7 = "STREAM\n") */
1094
if (send(sock, "STREAM\n", 7, 0) < 0) {
1096
log_write(0, LOG_MAIN|LOG_PANIC,"malware acl condition: clamd: unable to write to socket (%s)",
1100
memset(av_buffer2, 0, sizeof(av_buffer2));
1101
bread = read(sock, av_buffer2, sizeof(av_buffer2));
1104
log_write(0, LOG_MAIN|LOG_PANIC,
1105
"malware acl condition: clamd: unable to read PORT from socket (%s)",
1110
if (bread == sizeof(av_buffer)) {
1111
log_write(0, LOG_MAIN|LOG_PANIC,
1112
"malware acl condition: clamd: buffer too small");
1116
if (!(*av_buffer2)) {
1117
log_write(0, LOG_MAIN|LOG_PANIC,
1118
"malware acl condition: clamd: ClamAV returned null");
1122
av_buffer2[bread] = '\0';
1123
if( sscanf(CS av_buffer2, "PORT %u\n", &port) != 1 ) {
1124
log_write(0, LOG_MAIN|LOG_PANIC,
1125
"malware acl condition: clamd: Expected port information from clamd, got '%s'", av_buffer2);
1129
if ( (sockData = ip_socket(SOCK_STREAM, AF_INET)) < 0) {
1130
log_write(0, LOG_MAIN|LOG_PANIC,
1131
"malware acl condition: clamd: unable to acquire socket (%s)",
1136
if (ip_connect(sockData, AF_INET, (uschar*)inet_ntoa(in), port, 5) < 0) {
1137
(void)close(sockData);
1138
log_write(0, LOG_MAIN|LOG_PANIC,
1139
"malware acl condition: clamd: connection to %s, port %u failed (%s)",
1140
inet_ntoa(in), port, strerror(errno));
1144
snprintf(CS scanrequest, 1024,CS"%s/scan/%s/%s.eml",
1145
spool_directory, message_id, message_id);
1147
/* calc file size */
1148
clam_fd = open(CS scanrequest, O_RDONLY);
1149
if (clam_fd == -1) {
1150
log_write(0, LOG_MAIN|LOG_PANIC,
1151
"malware acl condition: clamd: can't open spool file %s: %s",
1152
scanrequest, strerror(errno));
1155
fsize = lseek(clam_fd, 0, SEEK_END);
1157
log_write(0, LOG_MAIN|LOG_PANIC,
1158
"malware acl condition: clamd: can't seek spool file %s: %s",
1159
scanrequest, strerror(errno));
1162
lseek(clam_fd, 0, SEEK_SET);
1164
clamav_fbuf = (uschar *) malloc (fsize);
1166
(void)close(sockData);
1167
(void)close(clam_fd);
1168
log_write(0, LOG_MAIN|LOG_PANIC,
1169
"malware acl condition: clamd: unable to allocate memory %u for file (%s)",
1170
fsize, scanrequest);
1174
result = read (clam_fd, clamav_fbuf, fsize);
1176
(void)close(sockData);
1177
(void)close(clam_fd);
1179
log_write(0, LOG_MAIN|LOG_PANIC,
1180
"malware acl condition: clamd: can't read spool file %s: %s",
1181
scanrequest, strerror(errno));
1184
(void)close(clam_fd);
1186
/* send file body to socket */
1187
if (send(sockData, clamav_fbuf, fsize, 0) < 0) {
1188
(void)close(sockData);
1190
log_write(0, LOG_MAIN|LOG_PANIC,
1191
"malware acl condition: clamd: unable to send file body to socket (%s:%u)", hostname, port);
1195
(void)close(sockData);
1199
/* open the local socket */
1200
if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
1201
log_write(0, LOG_MAIN|LOG_PANIC,
1202
"malware acl condition: clamd: unable to acquire socket (%s)",
1207
server.sun_family = AF_UNIX;
1208
Ustrcpy(server.sun_path, clamd_options);
1210
if (connect(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) < 0) {
1212
log_write(0, LOG_MAIN|LOG_PANIC,
1213
"malware acl condition: clamd: unable to connect to UNIX socket %s (%s)",
1214
clamd_options, strerror(errno) );
1219
/* Pass the string to ClamAV (7 = "SCAN \n" + \0) */
1221
snprintf(CS file_name,1024,"SCAN %s/scan/%s\n", spool_directory, message_id);
1223
if (send(sock, file_name, Ustrlen(file_name), 0) < 0) {
1225
log_write(0, LOG_MAIN|LOG_PANIC,"malware acl condition: clamd: unable to write to socket (%s)",
1231
We're done sending, close socket for writing.
1233
One user reported that clamd 0.70 does not like this any more ...
1237
/* shutdown(sock, SHUT_WR); */
1239
/* Read the result */
1240
memset(av_buffer, 0, sizeof(av_buffer));
1241
bread = read(sock, av_buffer, sizeof(av_buffer));
1245
log_write(0, LOG_MAIN|LOG_PANIC,
1246
"malware acl condition: clamd: unable to read from socket (%s)",
1251
if (bread == sizeof(av_buffer)) {
1252
log_write(0, LOG_MAIN|LOG_PANIC,
1253
"malware acl condition: clamd: buffer too small");
1257
/* Check the result. ClamAV Returns
1258
infected: -> "<filename>: <virusname> FOUND"
1259
not-infected: -> "<filename>: OK"
1260
error: -> "<filename>: <errcode> ERROR */
1262
if (!(*av_buffer)) {
1263
log_write(0, LOG_MAIN|LOG_PANIC,
1264
"malware acl condition: clamd: ClamAV returned null");
1268
/* colon in returned output? */
1269
if((p = Ustrrchr(av_buffer,':')) == NULL) {
1270
log_write(0, LOG_MAIN|LOG_PANIC,
1271
"malware acl condition: clamd: ClamAV returned malformed result: %s",
1276
/* strip filename strip CR at the end */
1278
while (*p == ' ') ++p;
1280
p = vname + Ustrlen(vname) - 1;
1281
if( *p == '\n' ) *p = '\0';
1283
if ((p = Ustrstr(vname, "FOUND"))!=NULL) {
1285
for (--p;p>vname && *p<=32;p--) *p=0;
1286
for (;*vname==32;vname++);
1287
Ustrcpy(malware_name_buffer,vname);
1288
malware_name = malware_name_buffer;
1291
if (Ustrstr(vname, "ERROR")!=NULL) {
1292
/* ClamAV reports ERROR
1294
for (;*vname!='\n' && vname>av_buffer; vname--);
1295
if (*vname=='\n') vname++;
1297
log_write(0, LOG_MAIN|LOG_PANIC,
1298
"malware acl condition: clamd: ClamAV returned %s",vname);
1302
/* Everything should be OK */
1303
malware_name = NULL;
1307
/* ----------------------------------------------------------------------- */
1310
/* "mksd" scanner type --------------------------------------------------- */
1311
else if (strcmpic(scanner_name,US"mksd") == 0) {
1312
uschar *mksd_options;
1313
char *mksd_options_end;
1314
uschar mksd_options_buffer[32];
1315
int mksd_maxproc = 1; /* default, if no option supplied */
1316
struct sockaddr_un server;
1320
if ((mksd_options = string_nextinlist(&av_scanner_work, &sep,
1321
mksd_options_buffer,
1322
sizeof(mksd_options_buffer))) != NULL) {
1323
mksd_maxproc = (int) strtol(CS mksd_options, &mksd_options_end, 10);
1324
if ((*mksd_options == '\0') || (*mksd_options_end != '\0') ||
1325
(mksd_maxproc < 1) || (mksd_maxproc > 32)) {
1326
log_write(0, LOG_MAIN|LOG_PANIC,
1327
"malware acl condition: mksd: invalid option '%s'", mksd_options);
1332
/* open the mksd socket */
1333
sock = socket(AF_UNIX, SOCK_STREAM, 0);
1335
log_write(0, LOG_MAIN|LOG_PANIC,
1336
"malware acl condition: can't open UNIX socket.");
1339
server.sun_family = AF_UNIX;
1340
Ustrcpy(server.sun_path, "/var/run/mksd/socket");
1341
if (connect(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) < 0) {
1343
log_write(0, LOG_MAIN|LOG_PANIC,
1344
"malware acl condition: unable to connect to mksd UNIX socket (/var/run/mksd/socket). errno=%d", errno);
1348
malware_name = NULL;
1350
retval = mksd_scan_packed(sock);
1355
/* ----------------------------------------------------------------------- */
1357
/* "unknown" scanner type ------------------------------------------------- */
1359
log_write(0, LOG_MAIN|LOG_PANIC,
1360
"malware condition: unknown scanner type '%s'", scanner_name);
1363
/* ----------------------------------------------------------------------- */
1365
/* set "been here, done that" marker */
1369
/* match virus name against pattern (caseless ------->----------v) */
1370
if ( (malware_name != NULL) &&
1371
(regex_match_and_setup(re, malware_name, 0, -1)) ) {
1380
/* simple wrapper for reading lines from sockets */
1381
int recv_line(int sock, uschar *buffer, int size) {
1384
memset(buffer,0,size);
1386
while(recv(sock,p,1,0) > -1) {
1387
if ((p-buffer) > (size-2)) break;
1388
if (*p == '\n') break;
1389
if (*p != '\r') p++;
1397
/* ============= private routines for the "mksd" scanner type ============== */
1399
#include <sys/uio.h>
1401
int mksd_writev (int sock, struct iovec *iov, int iovcnt)
1407
i = writev (sock, iov, iovcnt);
1408
while ((i < 0) && (errno == EINTR));
1411
log_write(0, LOG_MAIN|LOG_PANIC,
1412
"malware acl condition: unable to write to mksd UNIX socket (/var/run/mksd/socket)");
1417
if (i >= iov->iov_len) {
1424
iov->iov_base = CS iov->iov_base + i;
1430
int mksd_read_lines (int sock, uschar *av_buffer, int av_buffer_size)
1436
if ((i = recv (sock, av_buffer+offset, av_buffer_size-offset, 0)) <= 0) {
1438
log_write(0, LOG_MAIN|LOG_PANIC,
1439
"malware acl condition: unable to read from mksd UNIX socket (/var/run/mksd/socket)");
1444
/* offset == av_buffer_size -> buffer full */
1445
if (offset == av_buffer_size) {
1447
log_write(0, LOG_MAIN|LOG_PANIC,
1448
"malware acl condition: malformed reply received from mksd");
1451
} while (av_buffer[offset-1] != '\n');
1453
av_buffer[offset] = '\0';
1457
int mksd_parse_line (char *line)
1468
if ((p = strchr (line, '\n')) != NULL)
1470
log_write(0, LOG_MAIN|LOG_PANIC,
1471
"malware acl condition: mksd scanner failed: %s", line);
1475
if ((p = strchr (line, '\n')) != NULL) {
1477
if (((p-line) > 5) && ((p-line) < sizeof (malware_name_buffer)) && (line[3] == ' '))
1478
if (((p = strchr (line+4, ' ')) != NULL) && ((p-line) > 4)) {
1480
Ustrcpy (malware_name_buffer, line+4);
1481
malware_name = malware_name_buffer;
1485
log_write(0, LOG_MAIN|LOG_PANIC,
1486
"malware acl condition: malformed reply received from mksd: %s", line);
1491
int mksd_scan_packed (int sock)
1493
struct iovec iov[7];
1494
char *cmd = "MSQ/scan/.eml\n";
1495
uschar av_buffer[1024];
1497
iov[0].iov_base = cmd;
1499
iov[1].iov_base = CS spool_directory;
1500
iov[1].iov_len = Ustrlen (spool_directory);
1501
iov[2].iov_base = cmd + 3;
1503
iov[3].iov_base = iov[5].iov_base = CS message_id;
1504
iov[3].iov_len = iov[5].iov_len = Ustrlen (message_id);
1505
iov[4].iov_base = cmd + 3;
1507
iov[6].iov_base = cmd + 9;
1510
if (mksd_writev (sock, iov, 7) < 0)
1513
if (mksd_read_lines (sock, av_buffer, sizeof (av_buffer)) < 0)
1518
return mksd_parse_line (CS av_buffer);