shared/clamdcom.c
b59c7608
 /*
e1cbc270
  *  Copyright (C) 2013-2019 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
  *  Copyright (C) 2009-2013 Sourcefire, Inc.
b59c7608
  *
  *  Author: aCaB
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License version 2 as
  *  published by the Free Software Foundation.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  *  MA 02110-1301, USA.
  */
 
 #if HAVE_CONFIG_H
 #include "clamav-config.h"
 #endif
 
 #include <stdio.h>
 #include <string.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #if HAVE_UNISTD_H
 #include <unistd.h>
 #endif
 #include <fcntl.h>
 #include <errno.h>
 
6df13d04
 #if !defined(_WIN32)
 #include <sys/socket.h>
 #endif
 
b59c7608
 #include "shared/output.h"
 #include "shared/clamdcom.h"
 
 /* Sends bytes over a socket
  * Returns 0 on success */
288057e9
 int sendln(int sockd, const char *line, unsigned int len)
 {
     while (len) {
         int sent = send(sockd, line, len, 0);
         if (sent <= 0) {
             if (sent && errno == EINTR) continue;
             logg("!Can't send to clamd: %s\n", strerror(errno));
             return 1;
         }
         line += sent;
         len -= sent;
b59c7608
     }
     return 0;
 }
 
 /* Inits a RECVLN struct before it can be used in recvln() - see below */
288057e9
 void recvlninit(struct RCVLN *s, int sockd)
 {
b59c7608
     s->sockd = sockd;
     s->bol = s->cur = s->buf;
288057e9
     s->r            = 0;
b59c7608
 }
 
 /* Receives a full (terminated with \0) line from a socket
  * Sets rbol to the begin of the received line, and optionally 
  * reol to the end of line.
d245138c
  * Should be called repeatedly until all input is consumed
b59c7608
  * Returns:
d245138c
  * - the length of the line (a positive number) on success
b59c7608
  * - 0 if the connection is closed
  * - -1 on error
  */
288057e9
 int recvln(struct RCVLN *s, char **rbol, char **reol)
 {
b59c7608
     char *eol;
 
288057e9
     while (1) {
         if (!s->r) {
             s->r = recv(s->sockd, s->cur, sizeof(s->buf) - (s->cur - s->buf), 0);
             if (s->r <= 0) {
                 if (s->r && errno == EINTR) {
                     s->r = 0;
                     continue;
                 }
                 if (s->r || s->cur != s->buf) {
                     *s->cur = '\0';
                     if (strcmp(s->buf, "UNKNOWN COMMAND\n"))
                         logg("!Communication error\n");
                     else
                         logg("!Command rejected by clamd (wrong clamd version?)\n");
                     return -1;
                 }
                 return 0;
             }
         }
         if ((eol = memchr(s->cur, 0, s->r))) {
             int ret = 0;
             eol++;
             s->r -= eol - s->cur;
             *rbol = s->bol;
             if (reol) *reol = eol;
             ret = eol - s->bol;
             if (s->r)
                 s->bol = s->cur = eol;
             else
                 s->bol = s->cur = s->buf;
             return ret;
         }
         s->r += s->cur - s->bol;
         if (!eol && s->r == sizeof(s->buf)) {
             logg("!Overlong reply from clamd\n");
             return -1;
         }
         if (!eol) {
             if (s->buf != s->bol) { /* old memmove sux */
                 memmove(s->buf, s->bol, s->r);
                 s->bol = s->buf;
             }
             s->cur = &s->bol[s->r];
             s->r   = 0;
         }
b59c7608
     }
 }