From c82907bf6bd800d697e556ad21efbf2e4d3f59dd Mon Sep 17 00:00:00 2001 From: Jeremy Harris Date: Mon, 20 Jan 2014 01:41:34 +0000 Subject: [PATCH] Log/return-defer: de-repeat strings --- src/src/malware.c | 806 +++++++++++++++++++++------------------------- 1 file changed, 366 insertions(+), 440 deletions(-) diff --git a/src/src/malware.c b/src/src/malware.c index 9d459bf3f..75c0ad21d 100644 --- a/src/src/malware.c +++ b/src/src/malware.c @@ -155,6 +155,76 @@ malware_in_file(uschar *eml_filename) } +static void +malware_errlog(const uschar * str) +{ + log_write(0, LOG_MAIN|LOG_PANIC, "malware acl condition: %s", str); +} +static int +malware_errlog_defer(const uschar * str) +{ + malware_errlog(str); + return DEFER; +} + +static int +m_scanner_errlog_defer(const uschar * scanner, const uschar * str) +{ + return malware_errlog_defer(string_sprintf("%s: %s", scanner, str)); +} + +static int +fprotd_errlog_defer(const uschar * str) +{ + return m_scanner_errlog_defer("f-protd", str); +} +static int +drweb_errlog_defer(const uschar * str) +{ + return m_scanner_errlog_defer("drweb", str); +} +static int +aves_errlog_defer(const uschar * str) +{ + return m_scanner_errlog_defer("aveserver", str); +} +static int +fsec_errlog_defer(const uschar * str) +{ + return m_scanner_errlog_defer("fsecure", str); +} +static int +kavd_errlog_defer(const uschar * str) +{ + return m_scanner_errlog_defer("kavdaemon", str); +} +static int +cmdl_errlog_defer(const uschar * str) +{ + return m_scanner_errlog_defer("commandline", str); +} +static int +soph_errlog_defer(const uschar * str) +{ + return m_scanner_errlog_defer("sophie", str); +} +static int +clmd_errlog_defer(const uschar * str) +{ + return m_scanner_errlog_defer("clamd", str); +} +static int +mksd_errlog_defer(const uschar * str) +{ + return m_scanner_errlog_defer("mksd", str); +} + +static void +clmd_errlog(const uschar * str) +{ + log_write(0, LOG_MAIN|LOG_PANIC, "malware acl condition: clamd: %s", str); +} + /************************************************* * Scan content for malware * *************************************************/ @@ -189,12 +259,9 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) /* make sure the eml mbox file is spooled up */ mbox_file = spool_mbox(&mbox_size, faking ? eml_filename : NULL); - if (mbox_file == NULL) { - /* error while spooling */ - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: error while creating mbox spool file"); - return DEFER; - }; + if (mbox_file == NULL) /* error while spooling */ + return malware_errlog_defer("error while creating mbox spool file"); + /* none of our current scanners need the mbox file as a stream, so we can close it right away */ (void)fclose(mbox_file); @@ -228,20 +295,18 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) /* compile the regex, see if it works */ re = pcre_compile(CS malware_regex, PCRE_COPT, (const char **)&rerror, &roffset, NULL); - if (re == NULL) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: regular expression error in '%s': %s at offset %d", malware_regex, rerror, roffset); - return DEFER; - }; + if (!re) + return malware_errlog_defer( + string_sprintf("regular expression error in '%s': %s at offset %d", + malware_regex, rerror, roffset)); /* if av_scanner starts with a dollar, expand it first */ if (*av_scanner == '$') { av_scanner_work = expand_string(av_scanner); - if (av_scanner_work == NULL) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: av_scanner starts with $, but expansion failed: %s", expand_string_message); - return DEFER; - } + if (!av_scanner_work) + return malware_errlog_defer( + string_sprintf("av_scanner starts with $, but expansion failed: %s", + expand_string_message)); else { debug_printf("Expanded av_scanner global: %s\n", av_scanner_work); /* disable result caching in this case */ @@ -255,13 +320,11 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) /* find the scanner type from the av_scanner option */ if ((scanner_name = string_nextinlist(&av_scanner_work, &sep, - scanner_name_buffer, - sizeof(scanner_name_buffer))) == NULL) { + scanner_name_buffer, + sizeof(scanner_name_buffer))) == NULL) { /* no scanner given */ - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: av_scanner configuration variable is empty"); - return DEFER; - }; + return malware_errlog_defer("av_scanner configuration variable is empty"); + } /* "f-protd" scanner type ----------------------------------------------- */ if (strcmpic(scanner_name, US"f-protd") == 0) { @@ -284,46 +347,37 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) /* extract host and port part */ if ( sscanf(CS fp_options, "%s %u-%u", hostname, &portlow, &porthigh) != 3 ) { - if ( sscanf(CS fp_options, "%s %u", hostname, &portlow) != 2 ) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: f-protd: invalid socket '%s'", fp_options); - return DEFER; - } + if ( sscanf(CS fp_options, "%s %u", hostname, &portlow) != 2 ) + return fprotd_errlog_defer( + string_sprintf("invalid socket '%s'", fp_options)); porthigh = portlow; } /* Lookup the host */ - if((he = gethostbyname(CS hostname)) == 0) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: f-protd: failed to lookup host '%s'", hostname); - return DEFER; - } + if((he = gethostbyname(CS hostname)) == 0) + return fprotd_errlog_defer( + string_sprintf("failed to lookup host '%s'", hostname)); in = *(struct in_addr *) he->h_addr_list[0]; port = portlow; /* Open the f-protd TCP socket */ - if ( (sock = ip_socket(SOCK_STREAM, AF_INET)) < 0) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: f-protd: unable to acquire socket (%s)", - strerror(errno)); - return DEFER; - } + if ( (sock = ip_socket(SOCK_STREAM, AF_INET)) < 0) + return fprotd_errlog_defer( + string_sprintf("unable to acquire socket (%s)", strerror(errno))); /* Try to connect to all portslow-high until connection is established */ - for (port = portlow; !connect_ok && port < porthigh; port++) { - if (ip_connect(sock, AF_INET, (uschar*)inet_ntoa(in), port, 5) >= 0) { + for (port = portlow; !connect_ok && port < porthigh; port++) + if (ip_connect(sock, AF_INET, (uschar*)inet_ntoa(in), port, 5) >= 0) connect_ok = 1; - } - } if ( !connect_ok ) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: f-protd: connection to %s, port %u-%u failed (%s)", - inet_ntoa(in), portlow, porthigh, strerror(errno)); + int err = errno; (void)close(sock); - return DEFER; + return fprotd_errlog_defer( + string_sprintf("connection to %s, port %u-%u failed (%s)", + inet_ntoa(in), portlow, porthigh, strerror(err))); } DEBUG(D_acl) debug_printf("Malware scan: issuing %s GET\n", scanner_name); @@ -342,13 +396,10 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) Ustrcat(scanrequest, " HTTP/1.0\r\n\r\n"); /* send scan request */ - if (send(sock, &scanrequest, Ustrlen(scanrequest)+1, 0) < 0) { + if (send(sock, &scanrequest, Ustrlen(scanrequest)+1, 0) < 0) (void)close(sock); - log_write(0, LOG_MAIN|LOG_PANIC, - "%s f-protd: unable to send command to socket (%s)", - mal_err, scanrequest); - return DEFER; - } + return fprotd_errlog_defer( + string_sprintf("unable to send command to socket (%s)", scanrequest)); /* We get a lot of empty lines, so we need this hack to check for any data at all */ while( recv(sock, buf, 1, MSG_PEEK) > 0 ) { @@ -395,35 +446,28 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) if (*drweb_options != '/') { /* extract host and port part */ - if( sscanf(CS drweb_options, "%s %u", hostname, &port) != 2 ) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: drweb: invalid socket '%s'", drweb_options); - return DEFER; - } + if( sscanf(CS drweb_options, "%s %u", hostname, &port) != 2 ) + return drweb_errlog_defer( + string_sprintf("invalid socket '%s'", drweb_options)); /* Lookup the host */ - if((he = gethostbyname(CS hostname)) == 0) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: drweb: failed to lookup host '%s'", hostname); - return DEFER; - } + if((he = gethostbyname(CS hostname)) == 0) + return drweb_errlog_defer( + string_sprintf("failed to lookup host '%s'", hostname)); in = *(struct in_addr *) he->h_addr_list[0]; /* Open the drwebd TCP socket */ - if ( (sock = ip_socket(SOCK_STREAM, AF_INET)) < 0) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: drweb: unable to acquire socket (%s)", - strerror(errno)); - return DEFER; - } + if ( (sock = ip_socket(SOCK_STREAM, AF_INET)) < 0) + return drweb_errlog_defer( + string_sprintf("unable to acquire socket (%s)", strerror(errno))); if (ip_connect(sock, AF_INET, (uschar*)inet_ntoa(in), port, 5) < 0) { + int err = errno; (void)close(sock); - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: drweb: connection to %s, port %u failed (%s)", - inet_ntoa(in), port, strerror(errno)); - return DEFER; + return drweb_errlog_defer( + string_sprintf("connection to %s, port %u failed (%s)", + inet_ntoa(in), port, strerror(err))); } /* prepare variables */ @@ -433,20 +477,20 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) /* calc file size */ drweb_fd = open(CS eml_filename, O_RDONLY); if (drweb_fd == -1) { + int err = errno; (void)close(sock); - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: drweb: can't open spool file %s: %s", - eml_filename, strerror(errno)); - return DEFER; + return drweb_errlog_defer( + string_sprintf("can't open spool file %s: %s", + eml_filename, strerror(err))); } fsize = lseek(drweb_fd, 0, SEEK_END); if (fsize == -1) { + int err = errno; (void)close(sock); (void)close(drweb_fd); - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: drweb: can't seek spool file %s: %s", - eml_filename, strerror(errno)); - return DEFER; + return drweb_errlog_defer( + string_sprintf("can't seek spool file %s: %s", + eml_filename, strerror(err))); } drweb_slen = htonl(fsize); lseek(drweb_fd, 0, SEEK_SET); @@ -461,30 +505,28 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) (send(sock, &drweb_slen, sizeof(drweb_slen), 0) < 0)) { (void)close(sock); (void)close(drweb_fd); - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: drweb: unable to send commands to socket (%s)", drweb_options); - return DEFER; + return drweb_errlog_defer( + string_sprintf("unable to send commands to socket (%s)", drweb_options)); } drweb_fbuf = (uschar *) malloc (fsize); if (!drweb_fbuf) { (void)close(sock); (void)close(drweb_fd); - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: drweb: unable to allocate memory %u for file (%s)", - fsize, eml_filename); - return DEFER; + return drweb_errlog_defer( + string_sprintf("unable to allocate memory %u for file (%s)", + fsize, eml_filename)); } result = read (drweb_fd, drweb_fbuf, fsize); if (result == -1) { + int err = errno; (void)close(sock); (void)close(drweb_fd); free(drweb_fbuf); - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: drweb: can't read spool file %s: %s", - eml_filename, strerror(errno)); - return DEFER; + return drweb_errlog_defer( + string_sprintf("can't read spool file %s: %s", + eml_filename, strerror(err))); } (void)close(drweb_fd); @@ -492,27 +534,23 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) if (send(sock, drweb_fbuf, fsize, 0) < 0) { (void)close(sock); free(drweb_fbuf); - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: drweb: unable to send file body to socket (%s)", drweb_options); - return DEFER; + return drweb_errlog_defer( + string_sprintf("unable to send file body to socket (%s)", drweb_options)); } (void)close(drweb_fd); } else { /* open the drwebd UNIX socket */ sock = socket(AF_UNIX, SOCK_STREAM, 0); - if (sock < 0) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: drweb: can't open UNIX socket"); - return DEFER; - } + if (sock < 0) + return drweb_errlog_defer("can't open UNIX socket"); server.sun_family = AF_UNIX; Ustrcpy(server.sun_path, drweb_options); if (connect(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) < 0) { + int err = errno; (void)close(sock); - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: drweb: unable to connect to socket (%s). errno=%d", drweb_options, errno); - return DEFER; + return drweb_errlog_defer( + string_sprintf("unable to connect to socket (%s). errno=%d", drweb_options, err)); } /* prepare variables */ @@ -530,26 +568,21 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) (send(sock, eml_filename, Ustrlen(eml_filename), 0) < 0) || (send(sock, &drweb_fin, sizeof(drweb_fin), 0) < 0)) { (void)close(sock); - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: drweb: unable to send commands to socket (%s)", drweb_options); - return DEFER; + return drweb_errlog_defer( + string_sprintf("unable to send commands to socket (%s)", drweb_options)); } } /* wait for result */ if ((bread = recv(sock, &drweb_rc, sizeof(drweb_rc), 0) != sizeof(drweb_rc))) { (void)close(sock); - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: drweb: unable to read return code"); - return DEFER; + return drweb_errlog_defer("unable to read return code"); } drweb_rc = ntohl(drweb_rc); if ((bread = recv(sock, &drweb_vnum, sizeof(drweb_vnum), 0) != sizeof(drweb_vnum))) { (void)close(sock); - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: drweb: unable to read the number of viruses"); - return DEFER; + return drweb_errlog_defer("unable to read the number of viruses"); } drweb_vnum = ntohl(drweb_vnum); @@ -573,18 +606,14 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) /* read the size of report */ if ((bread = recv(sock, &drweb_slen, sizeof(drweb_slen), 0) != sizeof(drweb_slen))) { (void)close(sock); - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: drweb: cannot read report size"); - return DEFER; + return drweb_errlog_defer("cannot read report size"); }; drweb_slen = ntohl(drweb_slen); /* read report body */ if ((bread = recv(sock, tmpbuf, drweb_slen, 0)) != drweb_slen) { (void)close(sock); - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: drweb: cannot read report string"); - return DEFER; + return drweb_errlog_defer("cannot read report string"); }; tmpbuf[drweb_slen] = '\0'; @@ -620,10 +649,9 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) * DERR_CRC_ERROR, DERR_READSOCKET, DERR_WRITE_ERR * and others are ignored */ if (drweb_s) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: drweb: drweb daemon retcode 0x%x (%s)", drweb_rc, drweb_s); (void)close(sock); - return DEFER; + return drweb_errlog_defer( + string_sprintf("drweb daemon retcode 0x%x (%s)", drweb_rc, drweb_s)); } /* no virus found */ malware_name = NULL; @@ -649,18 +677,16 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) /* open the aveserver socket */ sock = socket(AF_UNIX, SOCK_STREAM, 0); - if (sock < 0) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: can't open UNIX socket."); - return DEFER; - } + if (sock < 0) + return aves_errlog_defer("can't open UNIX socket."); + server.sun_family = AF_UNIX; Ustrcpy(server.sun_path, kav_options); if (connect(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) < 0) { + int err = errno; (void)close(sock); - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: unable to connect to aveserver UNIX socket (%s). errno=%d", kav_options, errno); - return DEFER; + return aves_errlog_defer( + string_sprintf("unable to connect to UNIX socket (%s). errno=%d", kav_options, err)); } /* read aveserver's greeting and see if it is ready (2xx greeting) */ @@ -669,10 +695,9 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) if (buf[0] != '2') { /* aveserver is having problems */ (void)close(sock); - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: aveserver is unavailable (Responded: %s).", ((buf[0] != 0) ? buf : (uschar *)"nothing") ); - return DEFER; - }; + return aves_errlog_defer( + string_sprintf("unavailable (Responded: %s).", ((buf[0] != 0) ? buf : (uschar *)"nothing") )); + } /* prepare our command */ (void)string_format(buf, 32768, "SCAN bPQRSTUW %s\r\n", eml_filename); @@ -682,9 +707,8 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) /* and send it */ if (send(sock, buf, Ustrlen(buf), 0) < 0) { (void)close(sock); - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: unable to write to aveserver UNIX socket (%s)", kav_options); - return DEFER; + return aves_errlog_defer( + string_sprintf("unable to write to UNIX socket (%s)", kav_options)); } malware_name = NULL; @@ -715,9 +739,8 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) /* and send it */ if (send(sock, buf, Ustrlen(buf), 0) < 0) { (void)close(sock); - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: unable to write to aveserver UNIX socket (%s)", kav_options); - return DEFER; + return aves_errlog_defer( + string_sprintf("unable to write to UNIX socket (%s)", kav_options)); } /* read aveserver's greeting and see if it is ready (2xx greeting) */ @@ -726,10 +749,9 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) if (buf[0] != '2') { /* aveserver is having problems */ (void)close(sock); - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: unable to quit aveserver dialogue (Responded: %s).", ((buf[0] != 0) ? buf : (uschar *)"nothing") ); - return DEFER; - }; + return aves_errlog_defer( + string_sprintf("unable to quit dialogue (Responded: %s).", ((buf[0] != 0) ? buf : (uschar *)"nothing") )); + } (void)close(sock); @@ -756,24 +778,23 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) sizeof(fsecure_options_buffer))) == NULL) { /* no options supplied, use default options */ fsecure_options = fsecure_options_default; - }; + } /* open the fsecure socket */ sock = socket(AF_UNIX, SOCK_STREAM, 0); - if (sock < 0) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: unable to open fsecure socket %s (%s)", - fsecure_options, strerror(errno)); - return DEFER; - } + if (sock < 0) + return fsec_errlog_defer( + string_sprintf("unable to open socket %s (%s)", + fsecure_options, strerror(errno))); + server.sun_family = AF_UNIX; Ustrcpy(server.sun_path, fsecure_options); if (connect(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) < 0) { + int err = errno; (void)close(sock); - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: unable to connect to fsecure socket %s (%s)", - fsecure_options, strerror(errno)); - return DEFER; + return fsec_errlog_defer( + string_sprintf("unable to connect to socket %s (%s)", + fsecure_options, strerror(err))); } DEBUG(D_acl) debug_printf("Malware scan: issuing %s scan [%s]\n", @@ -784,21 +805,21 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) for (i=0; i != 4; i++) { /* debug_printf("send option \"%s\"",cmdoptions[i]); */ if (write(sock, cmdoptions[i], Ustrlen(cmdoptions[i])) < 0) { + int err = errno; (void)close(sock); - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: unable to write fsecure option %d to %s (%s)", - i, fsecure_options, strerror(errno)); - return DEFER; - }; + return fsec_errlog_defer( + string_sprintf("unable to write option %d to %s (%s)", + i, fsecure_options, strerror(err))); + } bread = ip_recv(sock, av_buffer, sizeof(av_buffer), MALWARE_TIMEOUT); if (bread >0) av_buffer[bread]='\0'; if (bread < 0) { + int err = errno; (void)close(sock); - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: unable to read fsecure answer %d (%s)", i, strerror(errno)); - return DEFER; - }; + return fsec_errlog_defer( + string_sprintf("unable to read answer %d (%s)", i, strerror(errno))); + } for (j=0;j sizeof(file_name) - 1) - { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware filename does not fit in buffer [malware_internal() cmdline]"); - return DEFER; - } + return cmdl_errlog_defer("filename does not fit in buffer"); + Ustrcpy(file_name, eml_filename); p = Ustrrchr(file_name, '/'); if (p) *p = '\0'; fits = string_format(commandline, sizeof(commandline), CS cmdline_scanner, file_name); if (!fits) - { - log_write(0, LOG_MAIN|LOG_PANIC, - "cmdline scanner command-line does not fit in buffer"); - return DEFER; - } + return cmdl_errlog_defer("command-line does not fit in buffer"); /* redirect STDERR too */ if (Ustrlen(commandline) + 5 > sizeof(commandline)) - { - log_write(0, LOG_MAIN|LOG_PANIC, - "cmdline scanner command-line does not fit in buffer (STDERR redirect)"); - return DEFER; - } + return cmdl_errlog_defer("command-line does not fit in buffer (STDERR redirect)"); Ustrcat(commandline," 2>&1"); DEBUG(D_acl) debug_printf("Malware scan: issuing %s scan [%s]\n", scanner_name, commandline); @@ -1132,40 +1115,40 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) scanner_out = popen(CS commandline,"r"); if (scanner_out == NULL) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: calling cmdline scanner (%s) failed: %s.", commandline, strerror(errno)); + int err = errno; signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe); - return DEFER; - }; + return cmdl_errlog_defer( + string_sprintf("call (%s) failed: %s.", commandline, strerror(err))); + } (void)string_format(file_name,1024,"%s/scan/%s/%s_scanner_output", spool_directory, message_id, message_id); scanner_record = modefopen(file_name,"wb",SPOOL_MODE); if (scanner_record == NULL) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: opening scanner output file (%s) failed: %s.", file_name, strerror(errno)); + int err = errno; pclose(scanner_out); signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe); - return DEFER; - }; + return cmdl_errlog_defer( + string_sprintf("opening scanner output file (%s) failed: %s.", + file_name, strerror(err))); + } /* look for trigger while recording output */ while(fgets(CS linebuffer,32767,scanner_out) != NULL) { if ( Ustrlen(linebuffer) > fwrite(linebuffer, 1, Ustrlen(linebuffer), scanner_record) ) { /* short write */ - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: short write on scanner output file (%s).", file_name); pclose(scanner_out); signal(SIGCHLD,eximsigchld); signal(SIGPIPE,eximsigpipe); - return DEFER; - }; + return cmdl_errlog_defer( + string_sprintf("short write on scanner output file (%s).", file_name)); + } /* try trigger match */ if (!trigger && regex_match_and_setup(cmdline_trigger_re, linebuffer, 0, -1)) trigger = 1; - }; + } (void)fclose(scanner_record); pclose(scanner_out); @@ -1184,7 +1167,7 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) if (result >= 2) pcre_get_substring(CS linebuffer, ovector, result, 1, (const char **) &malware_name_internal); - }; + } (void)fclose(scanner_record); } else /* no virus found */ @@ -1214,18 +1197,17 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) /* open the sophie socket */ sock = socket(AF_UNIX, SOCK_STREAM, 0); - if (sock < 0) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: can't open UNIX socket."); - return DEFER; - } + if (sock < 0) + return soph_errlog_defer("can't open UNIX socket."); + server.sun_family = AF_UNIX; Ustrcpy(server.sun_path, sophie_options); if (connect(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) < 0) { + int err = errno; (void)close(sock); - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: unable to connect to sophie UNIX socket (%s). errno=%d", sophie_options, errno); - return DEFER; + return soph_errlog_defer( + string_sprintf("unable to connect to UNIX socket (%s). errno=%d", + sophie_options, err)); } /* pass the scan directory to sophie */ @@ -1233,9 +1215,7 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) if (len > sizeof(file_name)) { (void)close(sock); - log_write(0, LOG_MAIN|LOG_PANIC, - "malware filename does not fit in buffer [malware_internal() sophie]"); - return DEFER; + return soph_errlog_defer("malware filename does not fit in buffer"); } memcpy(file_name, eml_filename, len); p = Ustrrchr(file_name, '/'); @@ -1249,18 +1229,16 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) || write(sock, "\n", 1) != 1 ) { (void)close(sock); - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: unable to write to sophie UNIX socket (%s)", sophie_options); - return DEFER; + return soph_errlog_defer( + string_sprintf("unable to write to UNIX socket (%s)", sophie_options)); } /* wait for result */ memset(av_buffer, 0, sizeof(av_buffer)); if ((!(bread = ip_recv(sock, av_buffer, sizeof(av_buffer), MALWARE_TIMEOUT)) > 0)) { (void)close(sock); - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: unable to read from sophie UNIX socket (%s)", sophie_options); - return DEFER; + return soph_errlog_defer( + string_sprintf("unable to read from UNIX socket (%s)", sophie_options)); } (void)close(sock); @@ -1271,11 +1249,8 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) malware_name_internal = string_copy(&av_buffer[2]); malware_name = malware_name_internal; } - else if (!strncmp(CS av_buffer, "-1", 2)) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: malware acl condition: sophie reported error"); - return DEFER; - } + else if (!strncmp(CS av_buffer, "-1", 2)) + return soph_errlog_defer("scanner reported error"); else /* all ok, no virus */ malware_name = NULL; } @@ -1357,17 +1332,15 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) /* extract host and port part */ if( sscanf(CS address, "%" MAX_CLAMD_ADDRESS_LENGTH_S "s %u", this_clamd->tcp_addr, &(this_clamd->tcp_port)) != 2 ) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: clamd: invalid address '%s'", address); + clmd_errlog(string_sprintf("invalid address '%s'", address)); continue; } clamd_address_vector[num_servers] = this_clamd; num_servers++; if (num_servers >= MAX_CLAMD_SERVERS) { - log_write(0, LOG_MAIN|LOG_PANIC, - "More than " MAX_CLAMD_SERVERS_S " clamd servers specified; " - "only using the first " MAX_CLAMD_SERVERS_S ); + clmd_errlog("More than " MAX_CLAMD_SERVERS_S " clamd servers " + "specified; only using the first " MAX_CLAMD_SERVERS_S ); break; } } while ((address = string_nextinlist(&av_scanner_work, &sep, @@ -1375,21 +1348,16 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) sizeof(address_buffer))) != NULL); /* check if we have at least one server */ - if (!num_servers) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: clamd: no useable clamd server addresses in malware configuration option."); - return DEFER; - } + if (!num_servers) + return clmd_errlog_defer("no useable server addresses in malware configuration option."); } /* See the discussion of response formats below to see why we really don't like colons in filenames when passing filenames to ClamAV. */ - if (use_scan_command && Ustrchr(eml_filename, ':')) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: clamd: local/SCAN mode incompatible with" \ - " : in path to email filename [%s]", eml_filename); - return DEFER; - } + if (use_scan_command && Ustrchr(eml_filename, ':')) + return clmd_errlog_defer( + string_sprintf("local/SCAN mode incompatible with" \ + " : in path to email filename [%s]", eml_filename)); /* We have some network servers specified */ if (num_servers) { @@ -1410,10 +1378,8 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) * on both connections (as one host could resolve to multiple ips) */ if((he = gethostbyname(CS clamd_address_vector[current_server]->tcp_addr)) == 0) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: clamd: failed to lookup host '%s'", - clamd_address_vector[current_server]->tcp_addr - ); + clmd_errlog(string_sprintf("failed to lookup host '%s'", + clamd_address_vector[current_server]->tcp_addr)); goto try_next_server; } @@ -1421,9 +1387,8 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) /* Open the ClamAV Socket */ if ( (sock = ip_socket(SOCK_STREAM, AF_INET)) < 0) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: clamd: unable to acquire socket (%s)", - strerror(errno)); + clmd_errlog(string_sprintf("unable to acquire socket (%s)", + strerror(errno))); goto try_next_server; } @@ -1436,11 +1401,11 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) hostname = clamd_address_vector[current_server]->tcp_addr; break; } else { - log_write(0, LOG_MAIN|LOG_PANIC, + clmd_errlog(string_sprintf( "malware acl condition: clamd: connection to %s, port %u failed (%s)", clamd_address_vector[current_server]->tcp_addr, clamd_address_vector[current_server]->tcp_port, - strerror(errno)); + strerror(errno))); (void)close(sock); } @@ -1453,28 +1418,24 @@ try_next_server: clamd_address_vector[i] = clamd_address_vector[i+1]; } - if ( num_servers == 0 ) { - log_write(0, LOG_MAIN|LOG_PANIC, "malware acl condition: all clamd servers failed"); - return DEFER; - } + if ( num_servers == 0 ) + return clmd_errlog_defer("all servers failed"); + } else { /* open the local socket */ - if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: clamd: unable to acquire socket (%s)", - strerror(errno)); - return DEFER; - } + if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) + return clmd_errlog_defer( + string_sprintf("unable to acquire socket (%s)", strerror(errno))); server.sun_family = AF_UNIX; Ustrcpy(server.sun_path, clamd_options); if (connect(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) < 0) { + int err = errno; (void)close(sock); - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: clamd: unable to connect to UNIX socket %s (%s)", - clamd_options, strerror(errno) ); - return DEFER; + return clmd_errlog_defer( + string_sprintf("unable to connect to UNIX socket %s (%s)", + clamd_options, strerror(err) )); } } @@ -1495,58 +1456,53 @@ try_next_server: /* Pass the string to ClamAV (7 = "STREAM\n") */ if (send(sock, "STREAM\n", 7, 0) < 0) { - log_write(0, LOG_MAIN|LOG_PANIC,"malware acl condition: clamd: unable to write to socket (%s)", - strerror(errno)); + int err = errno; (void)close(sock); - return DEFER; + return clmd_errlog_defer( + string_sprintf("unable to write to socket (%s)", strerror(err))); } memset(av_buffer2, 0, sizeof(av_buffer2)); bread = ip_recv(sock, av_buffer2, sizeof(av_buffer2), MALWARE_TIMEOUT); if (bread < 0) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: clamd: unable to read PORT from socket (%s)", - strerror(errno)); + int err = errno; (void)close(sock); - return DEFER; + return clmd_errlog_defer( + string_sprintf("unable to read PORT from socket (%s)", + strerror(err))); } if (bread == sizeof(av_buffer)) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: clamd: buffer too small"); (void)close(sock); - return DEFER; + return clmd_errlog_defer("buffer too small"); } if (!(*av_buffer2)) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: clamd: ClamAV returned null"); (void)close(sock); - return DEFER; + return clmd_errlog_defer("ClamAV returned null"); } av_buffer2[bread] = '\0'; if( sscanf(CS av_buffer2, "PORT %u\n", &port) != 1 ) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: clamd: Expected port information from clamd, got '%s'", av_buffer2); (void)close(sock); - return DEFER; - }; + return clmd_errlog_defer( + string_sprintf("Expected port information from clamd, got '%s'", + av_buffer2)); + } if ( (sockData = ip_socket(SOCK_STREAM, AF_INET)) < 0) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: clamd: unable to acquire socket (%s)", - strerror(errno)); + int err = errno; (void)close(sock); - return DEFER; + return clmd_errlog_defer( + string_sprintf("unable to acquire socket (%s)", strerror(err))); } if (ip_connect(sockData, AF_INET, (uschar*)inet_ntoa(in), port, 5) < 0) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: clamd: connection to %s, port %u failed (%s)", - inet_ntoa(in), port, strerror(errno)); + int err = errno; (void)close(sockData); (void)close(sock); - return DEFER; + return clmd_errlog_defer( + string_sprintf("connection to %s, port %u failed (%s)", + inet_ntoa(in), port, strerror(err))); } #define CLOSE_SOCKDATA (void)close(sockData) @@ -1560,11 +1516,11 @@ try_next_server: /* Pass the string to ClamAV (10 = "zINSTREAM\0") */ if (send(sock, "zINSTREAM", 10, 0) < 0) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: clamd: unable to send zINSTREAM to socket (%s)", - strerror(errno)); + int err = errno; (void)close(sock); - return DEFER; + return clmd_errlog_defer( + string_sprintf("unable to send zINSTREAM to socket (%s)", + strerror(err))); } #define CLOSE_SOCKDATA /**/ @@ -1573,50 +1529,49 @@ try_next_server: /* calc file size */ clam_fd = open(CS eml_filename, O_RDONLY); if (clam_fd == -1) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: clamd: can't open spool file %s: %s", - eml_filename, strerror(errno)); + int err = errno; CLOSE_SOCKDATA; (void)close(sock); - return DEFER; + return clmd_errlog_defer( + string_sprintf("can't open spool file %s: %s", + eml_filename, strerror(err))); } fsize = lseek(clam_fd, 0, SEEK_END); if (fsize == -1) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: clamd: can't seek spool file %s: %s", - eml_filename, strerror(errno)); - CLOSE_SOCKDATA; (void)close(sock); - return DEFER; + int err = errno; + CLOSE_SOCKDATA; (void)close(sock); (void)close(clam_fd); + return clmd_errlog_defer( + string_sprintf("can't seek spool file %s: %s", + eml_filename, strerror(errno))); } lseek(clam_fd, 0, SEEK_SET); clamav_fbuf = (uschar *) malloc (fsize); if (!clamav_fbuf) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: clamd: unable to allocate memory %u for file (%s)", - fsize, eml_filename); CLOSE_SOCKDATA; (void)close(sock); (void)close(clam_fd); - return DEFER; + return clmd_errlog_defer( + string_sprintf("unable to allocate memory %u for file (%s)", + fsize, eml_filename)); } result = read (clam_fd, clamav_fbuf, fsize); if (result == -1) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: clamd: can't read spool file %s: %s", - eml_filename, strerror(errno)); + int err = errno; CLOSE_SOCKDATA; (void)close(sock); (void)close(clam_fd); free(clamav_fbuf); - return DEFER; + return clmd_errlog_defer( + string_sprintf("can't read spool file %s: %s", + eml_filename, strerror(err))); } (void)close(clam_fd); /* send file body to socket */ #ifdef WITH_OLD_CLAMAV_STREAM if (send(sockData, clamav_fbuf, fsize, 0) < 0) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: clamd: unable to send file body to socket (%s:%u)", hostname, port); CLOSE_SOCKDATA; (void)close(sock); free(clamav_fbuf); - return DEFER; + return clmd_errlog_defer( + string_sprintf("unable to send file body to socket (%s:%u)", + hostname, port); } #else send_size = htonl(fsize); @@ -1625,11 +1580,11 @@ try_next_server: (send(sock, clamav_fbuf, fsize, 0) < 0) || (send(sock, &send_final_zeroblock, sizeof(send_final_zeroblock), 0) < 0)) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: clamd: unable to send file body to socket (%s:%u)", hostname, port); (void)close(sock); free(clamav_fbuf); - return DEFER; + return clmd_errlog_defer( + string_sprintf("unable to send file body to socket (%s:%u)", + hostname, port)); } #endif @@ -1657,18 +1612,17 @@ try_next_server: eml_filename); if (!fits) { (void)close(sock); - log_write(0, LOG_MAIN|LOG_PANIC, - "malware filename does not fit in buffer [malware_internal() clamd]"); + clmd_errlog("filename does not fit in buffer"); } DEBUG(D_acl) debug_printf("Malware scan: issuing %s local-path scan [%s]\n", scanner_name, clamd_options); if (send(sock, file_name, Ustrlen(file_name), 0) < 0) { + int err = errno; (void)close(sock); - log_write(0, LOG_MAIN|LOG_PANIC,"malware acl condition: clamd: unable to write to socket (%s)", - strerror(errno)); - return DEFER; + return clmd_errlog_defer( + string_sprintf("unable to write to socket (%s)", strerror(err))); } /* Do not shut down the socket for writing; a user report noted that @@ -1682,18 +1636,12 @@ try_next_server: bread = ip_recv(sock, av_buffer, sizeof(av_buffer), MALWARE_TIMEOUT); (void)close(sock); - if (!(bread > 0)) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: clamd: unable to read from socket (%s)", - strerror(errno)); - return DEFER; - } + if (!(bread > 0)) + return clmd_errlog_defer( + string_sprintf("unable to read from socket (%s)", strerror(errno))); - if (bread == sizeof(av_buffer)) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: clamd: buffer too small"); - return DEFER; - } + if (bread == sizeof(av_buffer)) + return clmd_errlog_defer("buffer too small"); /* We're now assured of a NULL at the end of av_buffer */ /* Check the result. ClamAV returns one of two result formats. @@ -1716,11 +1664,8 @@ try_next_server: a colon. We will have whined loudly above if the eml_filename does (and we're passing a filename to clamd). */ - if (!(*av_buffer)) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: clamd: ClamAV returned null"); - return DEFER; - } + if (!(*av_buffer)) + return clmd_errlog_defer("ClamAV returned null"); /* strip newline at the end (won't be present for zINSTREAM) (also any trailing whitespace, which shouldn't exist, but we depend upon @@ -1736,12 +1681,10 @@ try_next_server: response_end = p; /* colon in returned output? */ - if((p = Ustrchr(av_buffer,':')) == NULL) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: clamd: ClamAV returned malformed result (missing colon): %s", - av_buffer); - return DEFER; - } + if((p = Ustrchr(av_buffer,':')) == NULL) + return clmd_errlog_defer( + string_sprintf("ClamAV returned malformed result (missing colon): %s", + av_buffer)); /* strip filename */ while (*p && isspace(*++p)) /**/; @@ -1769,23 +1712,18 @@ try_next_server: malware_name = malware_name_internal; DEBUG(D_acl) debug_printf("Malware found, name \"%s\"\n", malware_name); - } else if (Ustrcmp(result_tag, "ERROR") == 0) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: clamd: ClamAV returned: %s", - av_buffer); - return DEFER; + } else if (Ustrcmp(result_tag, "ERROR") == 0) + return clmd_errlog_defer( + string_sprintf("ClamAV returned: %s", av_buffer)); - } else if (Ustrcmp(result_tag, "OK") == 0) { + else if (Ustrcmp(result_tag, "OK") == 0) { /* Everything should be OK */ malware_name = NULL; DEBUG(D_acl) debug_printf("Malware not found\n"); - } else { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: clamd: unparseable response from ClamAV: {%s}", - av_buffer); - return DEFER; - } + } else + return clmd_errlog_defer( + string_sprintf("unparseable response from ClamAV: {%s}", av_buffer)); } /* clamd */ @@ -1807,27 +1745,23 @@ try_next_server: sizeof(mksd_options_buffer))) != NULL) { mksd_maxproc = (int) strtol(CS mksd_options, &mksd_options_end, 10); if ((*mksd_options == '\0') || (*mksd_options_end != '\0') || - (mksd_maxproc < 1) || (mksd_maxproc > 32)) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: mksd: invalid option '%s'", mksd_options); - return DEFER; - } + (mksd_maxproc < 1) || (mksd_maxproc > 32)) + return mksd_errlog_defer( + string_sprintf("invalid option '%s'", mksd_options)); } /* open the mksd socket */ sock = socket(AF_UNIX, SOCK_STREAM, 0); - if (sock < 0) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: can't open UNIX socket."); - return DEFER; - } + if (sock < 0) + return mksd_errlog_defer("can't open UNIX socket."); + server.sun_family = AF_UNIX; Ustrcpy(server.sun_path, "/var/run/mksd/socket"); if (connect(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) < 0) { + int err = errno; (void)close(sock); - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: unable to connect to mksd UNIX socket (/var/run/mksd/socket). errno=%d", errno); - return DEFER; + return mksd_errlog_defer( + string_sprintf("unable to connect to mksd UNIX socket (/var/run/mksd/socket). errno=%d", err)); } malware_name = NULL; @@ -1842,11 +1776,9 @@ try_next_server: /* ----------------------------------------------------------------------- */ /* "unknown" scanner type ------------------------------------------------- */ - else { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware condition: unknown scanner type '%s'", scanner_name); - return DEFER; - }; + else + return malware_errlog_defer(string_sprintf("unknown scanner type '%s'", + scanner_name)); /* ----------------------------------------------------------------------- */ /* set "been here, done that" marker */ @@ -1899,8 +1831,7 @@ mksd_writev (int sock, struct iovec *iov, int iovcnt) while ((i < 0) && (errno == EINTR)); if (i <= 0) { close (sock); - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: unable to write to mksd UNIX socket (/var/run/mksd/socket)"); + malware_errlog("unable to write to mksd UNIX socket (/var/run/mksd/socket)"); return -1; } @@ -1927,8 +1858,7 @@ mksd_read_lines (int sock, uschar *av_buffer, int av_buffer_size) do { if ((i = recv (sock, av_buffer+offset, av_buffer_size-offset, 0)) <= 0) { close (sock); - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: unable to read from mksd UNIX socket (/var/run/mksd/socket)"); + malware_errlog("unable to read from mksd UNIX socket (/var/run/mksd/socket)"); return -1; } @@ -1936,8 +1866,7 @@ mksd_read_lines (int sock, uschar *av_buffer, int av_buffer_size) /* offset == av_buffer_size -> buffer full */ if (offset == av_buffer_size) { close (sock); - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: malformed reply received from mksd"); + malware_errlog("malformed reply received from mksd"); return -1; } } while (av_buffer[offset-1] != '\n'); @@ -1959,9 +1888,7 @@ mksd_parse_line (char *line) case 'A': /* ERR */ if ((p = strchr (line, '\n')) != NULL) *p = '\0'; - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: mksd scanner failed: %s", line); - return DEFER; + return mksd_errlog_defer(string_sprintf("scanner failed: %s", line)); default: /* VIR */ if ((p = strchr (line, '\n')) != NULL) { @@ -1974,9 +1901,8 @@ mksd_parse_line (char *line) return OK; } } - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: malformed reply received from mksd: %s", line); - return DEFER; + return mksd_errlog_defer( + string_sprintf("malformed reply received from mksd: %s", line)); } } -- 2.30.2