[exim-cvs] cvs commit: exim/exim-src/src malware.c

Góra strony
Delete this message
Reply to this message
Autor: Tom Kistner
Data:  
Dla: exim-cvs
Temat: [exim-cvs] cvs commit: exim/exim-src/src malware.c
tom 2005/01/05 13:33:59 GMT

  Modified files:
    exim-src/src         malware.c 
  Log:
  Added patches for remote clamd operation and improved drwebd error handling. Contributed by Alex Miller


  Revision  Changes    Path
  1.4       +160 -1    exim/exim-src/src/malware.c


  Index: malware.c
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/malware.c,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- malware.c    17 Dec 2004 14:52:44 -0000    1.3
  +++ malware.c    5 Jan 2005 13:33:58 -0000    1.4
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/malware.c,v 1.3 2004/12/17 14:52:44 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/malware.c,v 1.4 2005/01/05 13:33:58 tom Exp $ */


   /*************************************************
   *     Exim - an Internet mail transport agent    *
  @@ -24,6 +24,11 @@
   #define DRWEBD_RETURN_VIRUSES       (1<<0)   /* ask daemon return to us viruses names from report */
   #define DRWEBD_IS_MAIL              (1<<19)  /* say to daemon that format is "archive MAIL" */


  +#define DERR_READ_ERR               (1<<0)   /* read error */
  +#define DERR_NOMEMORY               (1<<2)   /* no memory */
  +#define DERR_TIMEOUT                (1<<9)   /* scan timeout has run out */
  +#define DERR_BAD_CALL               (1<<15)  /* wrong command */
  +
   /* Routine to check whether a system is big- or litte-endian. 
      Ripped from http://www.faqs.org/faqs/graphics/fileformats-faq/part4/section-7.html
      Needed for proper kavdaemon implementation. Sigh. */
  @@ -197,6 +202,7 @@
               /* calc file size */
               drweb_fd = open(CS scanrequest, O_RDONLY);
               if (drweb_fd == -1) {
  +                close(sock);
                   log_write(0, LOG_MAIN|LOG_PANIC,
                       "malware acl condition: drweb: can't open spool file %s: %s", 
                       scanrequest, strerror(errno));
  @@ -204,6 +210,8 @@
               }
               fsize = lseek(drweb_fd, 0, SEEK_END);
               if (fsize == -1) {
  +                close(sock);
  +                close(drweb_fd);
                   log_write(0, LOG_MAIN|LOG_PANIC,
                       "malware acl condition: drweb: can't seek spool file %s: %s", 
                       scanrequest, strerror(errno));
  @@ -238,21 +246,23 @@
               if (result == -1) {
                   close(sock);
                   close(drweb_fd);
  +                free(drweb_fbuf);
                   log_write(0, LOG_MAIN|LOG_PANIC,
                       "malware acl condition: drweb: can't read spool file %s: %s",
                       scanrequest, strerror(errno));
                   return DEFER; 
               }
  +            close(drweb_fd);

            
               /* send file body to socket */
               if (send(sock, drweb_fbuf, fsize, 0) < 0) {
                   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;
               }
               close(drweb_fd);
  -            free(drweb_fbuf);
           }
           else {
               /* open the drwebd UNIX socket */
  @@ -367,6 +377,22 @@
               }
           }
           else {
  +            char *drweb_s = NULL;
  +
  +            if (drweb_rc & DERR_READ_ERR) drweb_s = "read error";
  +            if (drweb_rc & DERR_NOMEMORY) drweb_s = "no memory";
  +            if (drweb_rc & DERR_TIMEOUT)  drweb_s = "timeout";
  +            if (drweb_rc & DERR_BAD_CALL) drweb_s = "wrong command";
  +            /* retcodes DERR_SYMLINK, DERR_NO_REGFILE, DERR_SKIPPED.
  +             * DERR_TOO_BIG, DERR_TOO_COMPRESSED, DERR_SPAM,
  +             * 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);
  +                close(sock);
  +                  return DEFER;
  +            }
               /* no virus found */
               malware_name = NULL;
           };
  @@ -956,6 +982,14 @@
         uschar hostname[256];
         struct hostent *he;
         struct in_addr in;
  +      uschar *clamd_options2;
  +      uschar clamd_options2_buffer[1024];
  +      uschar clamd_options2_default[] = "";
  +      uschar av_buffer2[1024];
  +      uschar *clamav_fbuf;
  +      uschar scanrequest[1024];
  +      int sockData, clam_fd, result;
  +      unsigned int fsize;


         if ((clamd_options = string_nextinlist(&av_scanner_work, &sep,
                                                clamd_options_buffer,
  @@ -963,6 +997,11 @@
           /* no options supplied, use default options */
           clamd_options = clamd_options_default;
         }
  +      if ((clamd_options2 = string_nextinlist(&av_scanner_work, &sep,
  +                                             clamd_options2_buffer,
  +                                             sizeof(clamd_options2_buffer))) == NULL) {
  +        clamd_options2 = clamd_options2_default;
  +      }


         /* socket does not start with '/' -> network socket */
         if (*clamd_options != '/') {
  @@ -997,6 +1036,126 @@
                       "malware acl condition: clamd: connection to %s, port %u failed (%s)",
                       inet_ntoa(in), port, strerror(errno));
             return DEFER;
  +        }
  +
  +        if (strcmpic(clamd_options2,US"local") == 0) {
  +
  +      /* Pass the string to ClamAV (7 = "SCAN \n" + \0) */
  +    
  +          snprintf(CS file_name,1024,"SCAN %s/scan/%s\n", spool_directory, message_id);
  +    
  +          if (send(sock, file_name, Ustrlen(file_name), 0) < 0) {
  +            close(sock);
  +            log_write(0, LOG_MAIN|LOG_PANIC,"malware acl condition: clamd: unable to write to socket (%s)",
  +                  strerror(errno));
  +            return DEFER;
  +          }
  +        } else {
  +
  +      /* Pass the string to ClamAV (7 = "STREAM\n") */
  +
  +          if (send(sock, "STREAM\n", 7, 0) < 0) {
  +            close(sock);
  +            log_write(0, LOG_MAIN|LOG_PANIC,"malware acl condition: clamd: unable to write to socket (%s)",
  +                  strerror(errno));
  +            return DEFER;
  +          }
  +          memset(av_buffer2, 0, sizeof(av_buffer2));
  +          bread = read(sock, av_buffer2, sizeof(av_buffer2));
  +
  +          if (bread < 0) {
  +            log_write(0, LOG_MAIN|LOG_PANIC,
  +                  "malware acl condition: clamd: unable to read PORT from socket (%s)",
  +                  strerror(errno));
  +            return DEFER;
  +          }
  +    
  +          if (bread == sizeof(av_buffer)) {
  +            log_write(0, LOG_MAIN|LOG_PANIC,
  +                  "malware acl condition: clamd: buffer too small");
  +            return DEFER;
  +          }
  +    
  +          if (!(*av_buffer2)) {
  +            log_write(0, LOG_MAIN|LOG_PANIC,
  +                  "malware acl condition: clamd: ClamAV returned null");
  +            return DEFER;
  +          }
  +    
  +          av_buffer2[bread] = '\0';
  +          if( sscanf(CS av_buffer2, "PORT %hu\n", &port) != 1 ) {
  +            log_write(0, LOG_MAIN|LOG_PANIC,
  +                    "malware acl condition: clamd: Expected port information from clamd, got '%s'", av_buffer2);
  +            return DEFER;
  +          };
  +    
  +          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));
  +            return DEFER;
  +          }
  +    
  +          if (ip_connect(sockData, AF_INET, (uschar*)inet_ntoa(in), port, 5) < 0) {
  +            close(sockData);
  +            log_write(0, LOG_MAIN|LOG_PANIC,
  +                    "malware acl condition: clamd: connection to %s, port %u failed (%s)",
  +                    inet_ntoa(in), port, strerror(errno));
  +            return DEFER;
  +          }
  +
  +        snprintf(CS scanrequest, 1024,CS"%s/scan/%s/%s.eml",
  +        spool_directory, message_id, message_id);
  +  
  +        /* calc file size */
  +        clam_fd = open(CS scanrequest, O_RDONLY);
  +        if (clam_fd == -1) {
  +          log_write(0, LOG_MAIN|LOG_PANIC,
  +                    "malware acl condition: clamd: can't open spool file %s: %s", 
  +              scanrequest, strerror(errno));
  +          return DEFER; 
  +        }
  +      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", 
  +              scanrequest, strerror(errno));
  +          return DEFER; 
  +        }
  +        lseek(clam_fd, 0, SEEK_SET);
  +  
  +        clamav_fbuf = (uschar *) malloc (fsize);
  +      if (!clamav_fbuf) {
  +        close(sockData);
  +          close(clam_fd);
  +          log_write(0, LOG_MAIN|LOG_PANIC,
  +            "malware acl condition: clamd: unable to allocate memory %u for file (%s)", 
  +              fsize, scanrequest);
  +          return DEFER;
  +        }
  +  
  +        result = read (clam_fd, clamav_fbuf, fsize);
  +        if (result == -1) {
  +          close(sockData);
  +          close(clam_fd);
  +          free(clamav_fbuf);
  +          log_write(0, LOG_MAIN|LOG_PANIC,
  +                "malware acl condition: clamd: can't read spool file %s: %s",
  +              scanrequest, strerror(errno));
  +          return DEFER; 
  +        }
  +        close(clam_fd);
  +
  +        /* send file body to socket */
  +        if (send(sockData, clamav_fbuf, fsize, 0) < 0) {
  +          close(sockData);
  +          free(clamav_fbuf);
  +          log_write(0, LOG_MAIN|LOG_PANIC,
  +            "malware acl condition: clamd: unable to send file body to socket (%s:%u)", hostname, port);
  +          return DEFER;
  +        }
  +        free(clamav_fbuf);
  +          close(sockData);
           }
         }
         else {