~ubuntu-branches/ubuntu/feisty/clamav/feisty

« back to all changes in this revision

Viewing changes to clamd/others.c

  • Committer: Bazaar Package Importer
  • Author(s): Kees Cook
  • Date: 2007-02-20 10:33:44 UTC
  • mto: This revision was merged to the branch mainline in revision 16.
  • Revision ID: james.westby@ubuntu.com-20070220103344-zgcu2psnx9d98fpa
Tags: upstream-0.90
ImportĀ upstreamĀ versionĀ 0.90

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
 
 *  Copyright (C) 2007-2009 Sourcefire, Inc.
3
 
 *
4
 
 *  Authors: Tomasz Kojm, Trog, Tƶrƶk Edvin
 
2
 *  Copyright (C) 2002 - 2005 Tomasz Kojm <tkojm@clamav.net>
5
3
 *
6
4
 *  This program is free software; you can redistribute it and/or modify
7
 
 *  it under the terms of the GNU General Public License version 2 as
8
 
 *  published by the Free Software Foundation.
 
5
 *  it under the terms of the GNU General Public License as published by
 
6
 *  the Free Software Foundation; either version 2 of the License, or
 
7
 *  (at your option) any later version.
9
8
 *
10
9
 *  This program is distributed in the hope that it will be useful,
11
10
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18
17
 *  MA 02110-1301, USA.
19
18
 */
20
19
 
 
20
#ifdef  _MSC_VER
 
21
#include <winsock.h>
 
22
#endif
 
23
 
21
24
#if HAVE_CONFIG_H
22
25
#include "clamav-config.h"
23
26
#endif
24
27
 
25
 
/* must be first because it may define _XOPEN_SOURCE */
26
 
#include "shared/fdpassing.h"
27
28
#include <stdio.h>
28
29
#include <stdarg.h>
29
30
#include <stdlib.h>
35
36
#include <time.h>
36
37
#include <sys/stat.h>
37
38
#include <errno.h>
38
 
#ifndef _WIN32
 
39
#ifndef C_WINDOWS
39
40
#include <sys/time.h>
40
41
#include <sys/wait.h>
 
42
#endif
 
43
 
 
44
#if HAVE_SYS_PARAM_H
 
45
#include <sys/param.h>
 
46
#endif
 
47
 
 
48
#ifndef C_WINDOWS
41
49
#include <sys/socket.h>
42
50
#include <sys/ioctl.h>
43
51
#endif
44
52
 
45
 
#if HAVE_SYS_PARAM_H
46
 
#include <sys/param.h>
47
 
#endif
48
 
 
49
53
#ifdef HAVE_SYS_TYPES_H
50
54
#include <sys/types.h>
51
55
#endif
52
56
#ifdef HAVE_SYS_FILIO_H
53
57
#include <sys/filio.h>
54
58
#endif
 
59
#ifdef HAVE_SYS_UIO_H
 
60
#include <sys/uio.h>
 
61
#endif
55
62
 
56
 
#include <pthread.h>
 
63
/* submitted by breiter@wolfereiter.com: do not use poll(2) on Interix */
 
64
#ifdef C_INTERIX
 
65
#undef HAVE_POLL
 
66
#undef HAVE_POLL_H
 
67
#endif
57
68
 
58
69
#if HAVE_POLL
59
70
#if HAVE_POLL_H
60
71
#include <poll.h>
61
72
#else /* HAVE_POLL_H */
 
73
#undef HAVE_POLL
62
74
#if HAVE_SYS_SELECT_H
63
75
#include <sys/select.h>
64
76
#endif /* HAVE_SYS_SELECT_H */
65
77
#endif /* HAVE_POLL_H */
66
78
#endif /* HAVE_POLL */
67
79
 
68
 
#include <limits.h>
69
 
#include "shared/optparser.h"
 
80
#include "shared/memory.h"
 
81
#include "shared/cfgparser.h"
70
82
#include "shared/output.h"
71
 
#include "shared/misc.h"
72
 
#include "libclamav/others.h"
73
83
 
74
84
#include "session.h"
75
85
#include "others.h"
76
86
 
77
 
static pthread_mutex_t virusaction_lock = PTHREAD_MUTEX_INITIALIZER;
78
 
static pthread_mutex_t detstats_lock = PTHREAD_MUTEX_INITIALIZER;
 
87
#define ENV_FILE  "CLAM_VIRUSEVENT_FILENAME"
 
88
#define ENV_VIRUS "CLAM_VIRUSEVENT_VIRUSNAME"
79
89
 
80
 
#ifdef  _WIN32
81
 
void virusaction(const char *filename, const char *virname, const struct optstruct *opts)
 
90
#ifdef  C_WINDOWS
 
91
void virusaction(const char *filename, const char *virname, const struct cfgstruct *copt)
82
92
{
83
 
    if(optget(opts, "VirusEvent")->enabled)
 
93
    if(cfgopt(copt, "VirusEvent")->enabled)
84
94
        logg("^VirusEvent is not supported on this platform");  /* Yet */
85
95
}
86
96
 
87
97
#else
88
98
 
89
 
#define VE_FILENAME  "CLAM_VIRUSEVENT_FILENAME"
90
 
#define VE_VIRUSNAME "CLAM_VIRUSEVENT_VIRUSNAME"
91
 
 
92
 
void virusaction(const char *filename, const char *virname, const struct optstruct *opts)
 
99
void virusaction(const char *filename, const char *virname, const struct cfgstruct *copt)
93
100
{
94
101
        pid_t pid;
95
 
        const struct optstruct *opt;
96
 
        char *buffer_file, *buffer_vir, *buffer_cmd;
97
 
        const char *pt;
98
 
        size_t i, j, v = 0, len;
99
 
        char *env[4];
100
 
 
101
 
        if(!(opt = optget(opts, "VirusEvent"))->enabled)
102
 
                return;
103
 
 
104
 
        env[0] = getenv("PATH");
105
 
        j = env[0] ? 1 : 0;
 
102
        struct cfgstruct *cpt;
 
103
 
 
104
    if(!(cpt = cfgopt(copt, "VirusEvent"))->enabled)
 
105
        return;
 
106
 
 
107
    /* NB: we need to fork here since this function modifies the environment. 
 
108
       (Modifications to the env. are not reentrant, but we need to be.) */
 
109
    pid = fork();
 
110
 
 
111
    if ( pid == 0 ) {
 
112
        /* child... */
 
113
        char *buffer, *pt, *cmd;
 
114
 
 
115
        cmd = strdup(cpt->strarg);
 
116
 
 
117
        if((pt = strstr(cmd, "%v"))) {
 
118
            buffer = (char *) mcalloc(strlen(cmd) + strlen(virname) + 10, sizeof(char));
 
119
            *pt = 0; pt += 2;
 
120
            strcpy(buffer, cmd);
 
121
            strcat(buffer, virname);
 
122
            strcat(buffer, pt);
 
123
            free(cmd);
 
124
            cmd = strdup(buffer);
 
125
            free(buffer);
 
126
        }
 
127
        
106
128
        /* Allocate env vars.. to be portable env vars should not be freed */
107
 
        buffer_file = (char *) malloc(strlen(VE_FILENAME) + strlen(filename) + 2);
108
 
        if(buffer_file) {
109
 
                sprintf(buffer_file, "%s=%s", VE_FILENAME, filename);
110
 
                env[j++] = buffer_file;
111
 
        }
112
 
 
113
 
        buffer_vir = (char *) malloc(strlen(VE_VIRUSNAME) + strlen(virname) + 2);
114
 
        if(buffer_vir) {
115
 
                sprintf(buffer_vir, "%s=%s", VE_VIRUSNAME, virname);
116
 
                env[j++] = buffer_vir;
117
 
        }
118
 
        env[j++] = NULL;
119
 
 
120
 
        pt = opt->strarg;
121
 
        while((pt = strstr(pt, "%v"))) {
122
 
            pt += 2;
123
 
            v++;
124
 
        }
125
 
        len = strlen(opt->strarg);
126
 
        buffer_cmd = (char *) calloc(len + v * strlen(virname) + 1, sizeof(char));
127
 
        if(!buffer_cmd) {
128
 
            free(buffer_file);
129
 
            free(buffer_vir);
130
 
            return;
131
 
        }
132
 
        for(i = 0, j = 0; i < len; i++) {
133
 
            if(i + 1 < len && opt->strarg[i] == '%' && opt->strarg[i + 1] == 'v') {
134
 
                strcat(buffer_cmd, virname);
135
 
                j += strlen(virname);
136
 
                i++;
137
 
            } else {
138
 
                buffer_cmd[j++] = opt->strarg[i];
139
 
            }
140
 
        }
141
 
 
142
 
        pthread_mutex_lock(&virusaction_lock);
143
 
        /* We can only call async-signal-safe functions after fork(). */
144
 
        pid = fork();
145
 
        if(!pid) { /* child */
146
 
            exit(execle("/bin/sh", "sh", "-c", buffer_cmd, NULL, env));
147
 
        } else if(pid > 0) { /* parent */
148
 
            pthread_mutex_unlock(&virusaction_lock);
149
 
            while(waitpid(pid, NULL, 0) == -1 && errno == EINTR);
150
 
        } else {
151
 
            logg("!VirusEvent: fork failed.\n");
152
 
        }
153
 
        free(buffer_cmd);
154
 
        free(buffer_file);
155
 
        free(buffer_vir);
156
 
}
157
 
#endif /* _WIN32 */
 
129
        buffer = (char *) mcalloc(strlen(ENV_FILE) + strlen(filename) + 2, sizeof(char));
 
130
        sprintf(buffer, "%s=%s", ENV_FILE, filename);
 
131
        putenv(buffer);
 
132
 
 
133
        buffer = (char *) mcalloc(strlen(ENV_VIRUS) + strlen(virname) + 2, sizeof(char));
 
134
        sprintf(buffer, "%s=%s", ENV_VIRUS, virname);
 
135
        putenv(buffer);
 
136
        
 
137
    
 
138
        /* WARNING: this is uninterruptable ! */
 
139
        exit(system(cmd));
 
140
        
 
141
        /* The below is not reached but is here for completeness to remind
 
142
           maintainers that this buffer is still allocated.. */
 
143
        free(cmd);
 
144
    } else if (pid > 0) {
 
145
        /* parent */      
 
146
        waitpid(pid, NULL, 0);
 
147
    } else {
 
148
        /* error.. */
 
149
        logg("!VirusAction: fork failed.\n");
 
150
    }
 
151
}
 
152
#endif /* C_WINDOWS */
 
153
 
 
154
int poll_fds(int *fds, int nfds, int timeout_sec)
 
155
{
 
156
        int retval;
 
157
        int i;
 
158
#ifdef HAVE_POLL
 
159
        struct pollfd poll_1[1];
 
160
        struct pollfd *poll_data = poll_1;
 
161
 
 
162
    if (nfds>1) {
 
163
        poll_data = mmalloc(nfds*sizeof(*poll_data));
 
164
        if(!poll_data) {
 
165
            logg("!poll_fds: Can't allocate memory for poll_data\n");
 
166
            return -1;
 
167
        }
 
168
    }
 
169
 
 
170
    for (i=0; i<nfds; i++) {
 
171
        poll_data[i].fd = fds[i];
 
172
        poll_data[i].events = POLLIN;
 
173
        poll_data[i].revents = 0;
 
174
    }
 
175
 
 
176
    if (timeout_sec > 0) {
 
177
        timeout_sec *= 1000;
 
178
    }
 
179
    while (1) {
 
180
        retval = poll(poll_data, nfds, timeout_sec);
 
181
        if (retval == -1) {
 
182
            if (errno == EINTR) {
 
183
                continue;
 
184
            }
 
185
            if (nfds>1)
 
186
                free(poll_data);
 
187
            return -1;
 
188
        }
 
189
        if (nfds>1) {
 
190
            if (retval>0) {
 
191
                for (i=0; i<nfds; i++) {
 
192
                    if (poll_data[i].revents) {
 
193
                        retval = i+1;
 
194
                        break;
 
195
                    }
 
196
                }
 
197
            }
 
198
            free(poll_data);
 
199
        }
 
200
        return retval;
 
201
    }
 
202
 
 
203
#else
 
204
        fd_set rfds;
 
205
        struct timeval tv;
 
206
        int maxfd = 0;
 
207
 
 
208
    for (i=0; i<nfds; i++) {
 
209
#ifndef C_WINDOWS
 
210
        if (fds[i] >= DEFAULT_FD_SETSIZE) {
 
211
            return -1;
 
212
        }
 
213
#endif
 
214
        if (fds[i] > maxfd)
 
215
            maxfd = fds[i];
 
216
    }
 
217
 
 
218
    while (1) {
 
219
        FD_ZERO(&rfds);
 
220
        for (i=0; i<nfds; i++)
 
221
            FD_SET(fds[i], &rfds);
 
222
        tv.tv_sec = timeout_sec;
 
223
        tv.tv_usec = 0;
 
224
 
 
225
        retval = select(maxfd+1, &rfds, NULL, NULL,
 
226
                        (timeout_sec>0 ? &tv : NULL));
 
227
        if (retval == -1) {
 
228
            if (errno == EINTR) {
 
229
                continue;
 
230
            }
 
231
            return -1;
 
232
        }
 
233
        if ((nfds>1) && (retval>0)) {
 
234
            for (i=0; i<nfds; i++) {
 
235
                if (FD_ISSET(fds[i],&rfds)) {
 
236
                    retval = i+1;
 
237
                    break;
 
238
                }
 
239
            }
 
240
        }
 
241
        return retval;
 
242
    }
 
243
#endif
 
244
 
 
245
    return -1;
 
246
}
 
247
 
 
248
int poll_fd(int fd, int timeout_sec)
 
249
{
 
250
    return poll_fds(&fd, 1, timeout_sec);
 
251
}
 
252
 
 
253
int is_fd_connected(int fd)
 
254
{
 
255
#ifdef HAVE_POLL
 
256
        struct pollfd poll_data[1];
 
257
        int count;
 
258
 
 
259
    poll_data[0].fd = fd;
 
260
    poll_data[0].events = POLLIN;
 
261
    poll_data[0].revents = 0;
 
262
 
 
263
    if ((count=poll(poll_data, 1, 0)) == -1) {
 
264
        if (errno == EINTR) {
 
265
                return 1;
 
266
        }
 
267
        return 0;
 
268
    }
 
269
    if (count == 0) {
 
270
        return 1;
 
271
    }
 
272
    if (poll_data[0].revents & POLLHUP) {
 
273
        return 0;
 
274
    }
 
275
    if ((poll_data[0].revents & POLLIN) && (ioctl(fd, FIONREAD, &count) == 0)) {
 
276
        if (count == 0) {
 
277
                return 0;
 
278
        }
 
279
    }
 
280
    return 1;
 
281
 
 
282
#else
 
283
        fd_set rfds;
 
284
        struct timeval tv;
 
285
        char buff[1];
 
286
 
 
287
#ifndef C_WINDOWS
 
288
    if (fd >= DEFAULT_FD_SETSIZE) {
 
289
        return 1;
 
290
    }
 
291
#endif
 
292
 
 
293
    FD_ZERO(&rfds);
 
294
    FD_SET(fd, &rfds);
 
295
    tv.tv_sec = 0;
 
296
    tv.tv_usec = 0;
 
297
    if (select(fd+1, &rfds, NULL, NULL, &tv) <= 0) {
 
298
        return 1;
 
299
    }
 
300
    if (FD_ISSET(fd, &rfds)) {
 
301
        if (recv(fd, buff, 1, MSG_PEEK) != 1) {
 
302
            return 0;
 
303
        }
 
304
    }
 
305
    return 1;
 
306
#endif
 
307
}
158
308
 
159
309
/* Function: writen
160
310
        Try hard to write the specified number of bytes
183
333
    return count;
184
334
}
185
335
 
186
 
static int realloc_polldata(struct fd_data *data)
187
 
{
188
 
#ifdef HAVE_POLL
189
 
    if (data->poll_data_nfds == data->nfds)
190
 
        return 0;
191
 
    if (data->poll_data)
192
 
        free(data->poll_data);
193
 
    data->poll_data = malloc(data->nfds*sizeof(*data->poll_data));
194
 
    if (!data->poll_data) {
195
 
        logg("!realloc_polldata: Memory allocation failed for poll_data\n");
196
 
        return -1;
197
 
    }
198
 
    data->poll_data_nfds = data->nfds;
199
 
#endif
200
 
    return 0;
201
 
}
202
 
 
203
 
int poll_fd(int fd, int timeout_sec, int check_signals)
204
 
{
205
 
    int ret;
206
 
    struct fd_data fds = FDS_INIT(NULL);
207
 
 
208
 
    if (fds_add(&fds, fd, 1, timeout_sec) == -1)
209
 
        return -1;
210
 
    do {
211
 
        ret = fds_poll_recv(&fds, timeout_sec, check_signals, NULL);
212
 
    } while (ret == -1 && errno == EINTR);
213
 
    fds_free(&fds);
214
 
    return ret;
215
 
}
216
 
 
217
 
void fds_cleanup(struct fd_data *data)
218
 
{
219
 
    struct fd_buf *newbuf;
220
 
    unsigned i,j;
221
 
 
222
 
    for (i=0,j=0;i < data->nfds; i++) {
223
 
        if (data->buf[i].fd < 0) {
224
 
            if (data->buf[i].buffer)
225
 
                free(data->buf[i].buffer);
226
 
            continue;
 
336
/* FD Support Submitted by Richard Lyons <frob-clamav*webcentral.com.au> */
 
337
/*
 
338
   This procedure does timed clamd command and delimited input processing.  
 
339
   It is complex for several reasons:
 
340
       1) FD commands are delivered on Unix domain sockets via recvnsg() on platforms which can do this.  
 
341
          These command messages are accompanied by a single byte of data which is a NUL character.
 
342
       2) Newline delimited commands are indicated by a command which is prefixed by an 'n' character.  
 
343
          This character serves to indicate that the command will contain a newline which will cause
 
344
          command data to be read until the command input buffer is full or a newline is encountered.
 
345
          Once the delimiter is encountered, the data is returned without the prefixing 'n' byte.
 
346
       3) Legacy clamd clients presented commands which may or may not have been delimited by a newline.
 
347
          If a command happens to be delimted by a newline, then only that command (and its newline) is
 
348
          read and passed back, otherwise, all data read (in a single read) which fits in the specified
 
349
          buffer will be returned.
 
350
*/
 
351
int readsock(int sockfd, char *buf, size_t size, unsigned char delim, int timeout_sec, int force_delim, int read_command)
 
352
{
 
353
        int fd;
 
354
        ssize_t n;
 
355
        size_t boff = 0;
 
356
        char *pdelim;
 
357
#ifdef HAVE_RECVMSG
 
358
        struct msghdr msg;
 
359
        struct iovec iov[1];
 
360
#endif
 
361
#ifdef HAVE_CONTROL_IN_MSGHDR
 
362
#ifndef CMSG_SPACE
 
363
#define CMSG_SPACE(len)     (_CMSG_ALIGN(sizeof(struct cmsghdr)) + _CMSG_ALIGN(len))
 
364
#endif
 
365
#ifndef CMSG_LEN
 
366
#define CMSG_LEN(len)       (_CMSG_ALIGN(sizeof(struct cmsghdr)) + (len))
 
367
#endif
 
368
        struct cmsghdr *cmsg;
 
369
        char tmp[CMSG_SPACE(sizeof(fd))];
 
370
#endif
 
371
        time_t starttime, timenow;
 
372
 
 
373
    time(&starttime);
 
374
    while(1) {
 
375
        time(&timenow);
 
376
        switch(poll_fd(sockfd, (timeout_sec && ((timeout_sec-(timenow-starttime)) > 0)) ? timeout_sec-(timenow-starttime) : 0)) {
 
377
            case 0: /* timeout */
 
378
                return -2;
 
379
            case -1:
 
380
                if(errno == EINTR)
 
381
                    continue;
 
382
                return -1;
227
383
        }
228
 
        if (i != j)
229
 
            data->buf[j] = data->buf[i];
230
 
        j++;
 
384
        break;
231
385
    }
232
 
    if (j == data->nfds)
233
 
        return;
234
 
    for (i = j ; i < data->nfds; i++)
235
 
        data->buf[i].fd = -1;
236
 
    data->nfds = j;
237
 
    logg("$Number of file descriptors polled: %u fds\n", (unsigned) data->nfds);
238
 
    /* Shrink buffer */
239
 
    newbuf = realloc(data->buf, j*sizeof(*newbuf));
240
 
    if(!j)
241
 
        data->buf = NULL;
242
 
    else if (newbuf)
243
 
        data->buf = newbuf;/* non-fatal if shrink fails */
244
 
}
245
 
 
246
 
static int read_fd_data(struct fd_buf *buf)
247
 
{
248
 
    ssize_t n;
249
 
 
250
 
    buf->got_newdata=1;
251
 
    if (!buf->buffer) /* listen-only socket */
252
 
        return 1;
253
 
 
254
 
    if (buf->off >= buf->bufsize)
255
 
        return -1;
256
 
 
257
 
   /* Read the pending packet, it may contain more than one command, but
258
 
    * that is to the cmdparser to handle. 
259
 
    * It will handle 1st command, and then move leftover to beginning of buffer
260
 
    */
261
 
#ifdef HAVE_FD_PASSING
262
 
  {
263
 
      struct msghdr msg;
264
 
      struct cmsghdr *cmsg;
265
 
      union {
266
 
       unsigned char buff[CMSG_SPACE(sizeof(int))];
267
 
       struct cmsghdr hdr;
268
 
      } b;
269
 
      struct iovec iov[1];
270
 
 
271
 
      if (buf->recvfd != -1) {
272
 
          logg("$Closing unclaimed FD: %d\n", buf->recvfd);
273
 
          close(buf->recvfd);
274
 
          buf->recvfd = -1;
275
 
      }
276
 
      memset(&msg, 0, sizeof(msg));
277
 
      iov[0].iov_base = buf->buffer + buf->off;
278
 
      iov[0].iov_len = buf->bufsize - buf->off;
279
 
      msg.msg_iov = iov;
280
 
      msg.msg_iovlen = 1;
281
 
      msg.msg_control = b.buff;
282
 
      msg.msg_controllen = sizeof(b.buff);
283
 
 
284
 
      n = recvmsg(buf->fd, &msg, 0);
285
 
      if (n < 0)
286
 
          return -1;
287
 
      if (msg.msg_flags & MSG_TRUNC) {
288
 
          logg("^Message truncated at %d bytes\n", (int)n);
289
 
          return -1;
290
 
      }
291
 
      if (msg.msg_flags & MSG_CTRUNC) {
292
 
          if (msg.msg_controllen > 0)
293
 
              logg("^Control message truncated at %d bytes, %d data read\n",
294
 
                   (int)msg.msg_controllen, (int)n);
295
 
          else
296
 
              logg("^Control message truncated, no control data received, %d bytes read"
297
 
#ifdef C_LINUX
298
 
                   "(Is SELinux/AppArmor enabled, and blocking file descriptor passing?)"
299
 
#endif
300
 
                   "\n",
301
 
                   (int)n);
302
 
          return -1;
303
 
      }
304
 
      if (msg.msg_controllen) {
305
 
          for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
306
 
               cmsg = CMSG_NXTHDR(&msg, cmsg)) {
307
 
              if (cmsg->cmsg_len == CMSG_LEN(sizeof(int)) &&
308
 
                  cmsg->cmsg_level == SOL_SOCKET &&
309
 
                  cmsg->cmsg_type == SCM_RIGHTS) {
310
 
                  if (buf->recvfd != -1) {
311
 
                      logg("$Unclaimed file descriptor received. closing: %d\n", buf->recvfd);
312
 
                      close(buf->recvfd);
313
 
                  }
314
 
                  buf->recvfd = *(int *)CMSG_DATA(cmsg);
315
 
                  logg("$Receveived a file descriptor: %d\n", buf->recvfd);
316
 
              }
317
 
          }
318
 
      }
319
 
  }
 
386
    n = recv(sockfd, buf, size, MSG_PEEK);
 
387
    if(read_command) {
 
388
        if((n >= 1) && (buf[0] == 0)) { /* FD message */
 
389
#ifdef HAVE_RECVMSG
 
390
            iov[0].iov_base = buf;
 
391
            iov[0].iov_len = size;
 
392
            memset(&msg, 0, sizeof(msg));
 
393
            msg.msg_iov = iov;
 
394
            msg.msg_iovlen = 1;
 
395
#endif
 
396
#ifdef HAVE_ACCRIGHTS_IN_MSGHDR
 
397
            msg.msg_accrights = (caddr_t)&fd;
 
398
            msg.msg_accrightslen = sizeof(fd);
 
399
#endif
 
400
#ifdef HAVE_CONTROL_IN_MSGHDR
 
401
            msg.msg_control = tmp;
 
402
            msg.msg_controllen = sizeof(tmp);
 
403
#endif
 
404
#if defined(HAVE_RECVMSG) && !defined(C_OS2) && !defined(INCOMPLETE_CMSG)
 
405
            n = recvmsg(sockfd, &msg, 0);
320
406
#else
321
 
   n = recv(buf->fd, buf->buffer + buf->off, buf->bufsize - buf->off,0);
322
 
   if (n < 0)
323
 
       return -1;
324
 
#endif
325
 
   buf->off += n;
326
 
   return n;
327
 
}
328
 
 
329
 
static int buf_init(struct fd_buf *buf, int listen_only, int timeout)
330
 
{
331
 
    buf->off = 0;
332
 
    buf->got_newdata = 0;
333
 
    buf->recvfd = -1;
334
 
    buf->mode = MODE_COMMAND;
335
 
    buf->id = 0;
336
 
    buf->dumpfd = -1;
337
 
    buf->chunksize = 0;
338
 
    buf->quota = 0;
339
 
    buf->dumpname = NULL;
340
 
    buf->group = NULL;
341
 
    buf->term = '\0';
342
 
    if (!listen_only) {
343
 
        if (!buf->buffer) {
344
 
            buf->bufsize = PATH_MAX+8;
345
 
            /* plus extra space for a \0 so we can make sure every command is \0
346
 
             * terminated */
347
 
            if (!(buf->buffer = malloc(buf->bufsize + 1))) {
348
 
                logg("!add_fd: Memory allocation failed for command buffer\n");
349
 
                return -1;
350
 
            }
351
 
        }
352
 
    } else {
353
 
        if (buf->buffer)
354
 
            free(buf->buffer);
355
 
        buf->bufsize = 0;
356
 
        buf->buffer = NULL;
357
 
    }
358
 
    if (timeout) {
359
 
        time(&buf->timeout_at);
360
 
        buf->timeout_at += timeout;
361
 
    } else {
362
 
        buf->timeout_at = 0;
363
 
    }
364
 
    return 0;
365
 
}
366
 
 
367
 
int fds_add(struct fd_data *data, int fd, int listen_only, int timeout)
368
 
{
369
 
    struct fd_buf *buf;
370
 
    unsigned n;
371
 
    if (fd < 0) {
372
 
        logg("!add_fd: invalid fd passed to add_fd\n");
373
 
        return -1;
374
 
    }
375
 
    /* we may already have this fd, if
376
 
     * the old FD got closed, and the kernel reused the FD */
377
 
    for (n = 0; n < data->nfds; n++)
378
 
        if (data->buf[n].fd == fd) {
379
 
            /* clear stale data in buffer */
380
 
            if (buf_init(&data->buf[n], listen_only, timeout) < 0)
381
 
                return -1;
382
 
            return 0;
383
 
        }
384
 
 
385
 
    n++;
386
 
    buf = realloc(data->buf, n*sizeof(*buf));
387
 
    if (!buf) {
388
 
        logg("!add_fd: Memory allocation failed for fd_buf\n");
389
 
        return -1;
390
 
    }
391
 
    data->buf = buf;
392
 
    data->nfds = n;
393
 
    data->buf[n-1].buffer = NULL;
394
 
    if (buf_init(&data->buf[n-1], listen_only, timeout) < 0)
395
 
        return -1;
396
 
    data->buf[n-1].fd = fd;
397
 
    return 0;
398
 
}
399
 
 
400
 
static inline void fds_lock(struct fd_data *data)
401
 
{
402
 
    if (data->buf_mutex)
403
 
        pthread_mutex_lock(data->buf_mutex);
404
 
}
405
 
 
406
 
static inline void fds_unlock(struct fd_data *data)
407
 
{
408
 
    if (data->buf_mutex)
409
 
        pthread_mutex_unlock(data->buf_mutex);
410
 
}
411
 
 
412
 
void fds_remove(struct fd_data *data, int fd)
413
 
{
414
 
    size_t i;
415
 
    fds_lock(data);
416
 
    if (data->buf) {
417
 
        for (i=0;i<data->nfds;i++) {
418
 
            if (data->buf[i].fd == fd) {
419
 
                data->buf[i].fd = -1;
 
407
            n = recv(sockfd, buf, size, 0);
 
408
#endif
 
409
            if (n <= 0)
 
410
                return n;
 
411
            errno = EBADF;
 
412
#ifdef HAVE_ACCRIGHTS_IN_MSGHDR
 
413
            if(msg.msg_accrightslen != sizeof(fd))
 
414
                return -1;
 
415
#endif
 
416
#ifdef HAVE_CONTROL_IN_MSGHDR
 
417
            cmsg = CMSG_FIRSTHDR(&msg);
 
418
            if(cmsg == NULL)
 
419
                return -1;
 
420
            if(cmsg->cmsg_type != SCM_RIGHTS)
 
421
                return -1;
 
422
            if(cmsg->cmsg_len != CMSG_LEN(sizeof(fd)))
 
423
                return -1;
 
424
            fd = *(int *)CMSG_DATA(cmsg);
 
425
#endif
 
426
            if(fd < 0)
 
427
                return -1;
 
428
            n = snprintf(buf, size, "FD %d", fd);
 
429
            if((size_t) n >= size)
 
430
                return -1;
 
431
            return n;
 
432
        }
 
433
        if((n >= 1) && (buf[0] == 'n')) { /* Newline delimited command */
 
434
            force_delim = 1;
 
435
            delim = '\n';
 
436
        }
 
437
    }
 
438
    while(boff < size) {
 
439
        if(force_delim) {
 
440
            pdelim = memchr(buf, delim, n+boff);
 
441
            if(pdelim) {
 
442
                n = recv(sockfd, buf+boff, pdelim-buf+1-boff, 0);
420
443
                break;
 
444
            } else {
 
445
                n = recv(sockfd, buf+boff, n, 0);
 
446
                if((boff+n) == size)
 
447
                    break;
 
448
                boff += n;
421
449
            }
422
 
        }
423
 
    }
424
 
    fds_unlock(data);
425
 
}
426
 
 
427
 
#define BUFFSIZE 1024
428
 
/* Wait till data is available to be read on any of the fds,
429
 
 * read available data on all fds, and mark them as appropriate.
430
 
 * One of the fds should be a pipe, used by the accept thread to wake us.
431
 
 * timeout is specified in seconds, if check_signals is non-zero, then
432
 
 * poll_recv_fds() will return upon receipt of a signal, even if no data
433
 
 * is received on any of the sockets.
434
 
 * Must be called with buf_mutex lock held.
435
 
 */
436
 
/* TODO: handle ReadTimeout */
437
 
int fds_poll_recv(struct fd_data *data, int timeout, int check_signals, void *event)
438
 
{
439
 
    unsigned fdsok = data->nfds;
440
 
    size_t i;
441
 
    int retval;
442
 
    time_t now, closest_timeout;
443
 
 
444
 
    /* we must have at least one fd, the control fd! */
445
 
    fds_cleanup(data);
446
 
#ifndef _WIN32
447
 
    if (!data->nfds)
448
 
        return 0;
449
 
#endif
450
 
    for (i=0;i < data->nfds;i++) {
451
 
        data->buf[i].got_newdata = 0;
452
 
    }
453
 
 
454
 
    time(&now);
455
 
    if (timeout > 0)
456
 
        closest_timeout = now + timeout;
457
 
    else
458
 
        closest_timeout = 0;
459
 
    for (i=0;i < data->nfds; i++) {
460
 
        time_t timeout_at = data->buf[i].timeout_at;
461
 
        if (timeout_at && timeout_at < now) {
462
 
            /* timed out */
463
 
            data->buf[i].got_newdata = -2;
464
 
            /* we must return immediately from poll/select, we have a timeout! */
465
 
            closest_timeout = now;
466
450
        } else {
467
 
            if (!closest_timeout)
468
 
                closest_timeout = timeout_at;
469
 
            else if (timeout_at && timeout_at < closest_timeout)
470
 
                closest_timeout = timeout_at;
 
451
            pdelim = memchr(buf, delim, n+boff);
 
452
            if(pdelim)
 
453
                n = recv(sockfd, buf+boff, pdelim-buf+1-boff, 0);
 
454
            else
 
455
                n = recv(sockfd, buf+boff, size-boff, 0);
 
456
            break;
471
457
        }
472
 
    }
473
 
    if (closest_timeout)
474
 
        timeout = closest_timeout - now;
475
 
    else
476
 
        timeout = -1;
477
 
    if (timeout > 0)
478
 
        logg("$fds_poll_recv: timeout after %d seconds\n", timeout);
479
 
#ifdef HAVE_POLL
480
 
    /* Use poll() if available, preferred because:
481
 
     *  - can poll any number of FDs
482
 
     *  - can notify of both data available / socket disconnected events
483
 
     *  - when it says POLLIN it is guaranteed that a following recv() won't
484
 
     *  block (select may say that data is available to read, but a following 
485
 
     *  recv() may still block according to the manpage
486
 
     */
487
 
 
488
 
    if (realloc_polldata(data) == -1)
489
 
        return -1;
490
 
    if (timeout > 0) {
491
 
        /* seconds to ms */
492
 
        timeout *= 1000;
493
 
    }
494
 
    for (i=0;i < data->nfds;i++) {
495
 
        data->poll_data[i].fd = data->buf[i].fd;
496
 
        data->poll_data[i].events = POLLIN;
497
 
        data->poll_data[i].revents = 0;
498
 
    }
499
 
    do {
500
 
        int n = data->nfds;
501
 
 
502
 
        fds_unlock(data);
503
 
#ifdef _WIN32
504
 
        retval = poll_with_event(data->poll_data, n, timeout, event);
505
 
#else
506
 
        retval = poll(data->poll_data, n, timeout);
507
 
#endif
508
 
        fds_lock(data);
509
 
 
510
 
        if (retval > 0) {
511
 
            fdsok = 0;
512
 
            /* nfds may change during poll, but not
513
 
             * poll_data_nfds */
514
 
            for (i=0;i < data->poll_data_nfds; i++) {
515
 
                short revents;
516
 
                if (data->buf[i].fd < 0)
517
 
                    continue;
518
 
                if (data->buf[i].fd != data->poll_data[i].fd) {
519
 
                    /* should never happen */
520
 
                    logg("!poll_recv_fds FD mismatch\n");
521
 
                    continue;
522
 
                }
523
 
                revents = data->poll_data[i].revents;
524
 
                if (revents & (POLLIN|POLLHUP)) {
525
 
                    logg("$Received POLLIN|POLLHUP on fd %d\n",data->poll_data[i].fd);
526
 
                }
527
 
#ifndef _WIN32
528
 
                if (revents & POLLHUP) {
529
 
                       /* avoid SHUT_WR problem on Mac OS X */
530
 
                       int ret = send(data->poll_data[i].fd, &n, 0, 0);
531
 
                       if (!ret || (ret == -1 && errno == EINTR))
532
 
                               revents &= ~POLLHUP;
533
 
                }
534
 
#endif
535
 
                if (revents & POLLIN) {
536
 
                    int ret = read_fd_data(&data->buf[i]);
537
 
                    /* Data available to be read */
538
 
                    if (ret == -1)
539
 
                        revents |= POLLERR;
540
 
                    else if (!ret)
541
 
                        revents = POLLHUP;
542
 
                }
543
 
 
544
 
                if (revents & (POLLHUP | POLLERR | POLLNVAL)) {
545
 
                    if (revents & (POLLHUP| POLLNVAL)) {
546
 
                        /* remote disconnected */
547
 
                        logg("*Client disconnected (FD %d)\n",
548
 
                             data->poll_data[i].fd);
549
 
                    } else {
550
 
                        /* error on file descriptor */
551
 
                        logg("^Error condition on fd %d\n",
552
 
                             data->poll_data[i].fd);
553
 
                    }
554
 
                    data->buf[i].got_newdata = -1;
555
 
                } else {
556
 
                    fdsok++;
557
 
                }
 
458
        while(1) {
 
459
            time(&timenow);
 
460
            switch(poll_fd(sockfd, ((timeout_sec-(timenow-starttime)) > 0) ? timeout_sec-(timenow-starttime) : 0)) {
 
461
                case 0: /* timeout */
 
462
                    return -2;
 
463
                case -1:
 
464
                    if(errno == EINTR)
 
465
                        continue;
 
466
                    return -1;
558
467
            }
 
468
            break;
559
469
        }
560
 
    } while (retval == -1 && !check_signals && errno == EINTR);
561
 
#else
562
 
    {
563
 
    fd_set rfds;
564
 
    struct timeval tv;
565
 
    int maxfd = -1;
566
 
 
567
 
    for (i=0;i < data->nfds; i++) {
568
 
        int fd = data->buf[i].fd;
569
 
        if (fd >= FD_SETSIZE) {
570
 
            logg ("!File descriptor is too high for FD_SET\n");
 
470
        n = recv(sockfd, buf+boff, size-boff, MSG_PEEK);
 
471
        if(n < 0)
571
472
            return -1;
572
 
        }
573
 
 
574
 
        maxfd = MAX(maxfd, fd);
575
 
    }
576
 
 
577
 
    do {
578
 
        FD_ZERO(&rfds);
579
 
        for(i=0;i < data->nfds;i++) {
580
 
            int fd = data->buf[i].fd;
581
 
            if (fd >= 0)
582
 
                FD_SET(fd, &rfds);
583
 
        }
584
 
        tv.tv_sec = timeout;
585
 
        tv.tv_usec = 0;
586
 
 
587
 
        fds_unlock(data);
588
 
        retval = select(maxfd+1, &rfds, NULL, NULL, timeout >= 0 ? &tv : NULL);
589
 
        fds_lock(data);
590
 
        if (retval > 0) {
591
 
            fdsok = data->nfds;
592
 
            for (i=0; i < data->nfds; i++) {
593
 
                if (data->buf[i].fd < 0) {
594
 
                    fdsok--;
595
 
                    continue;
596
 
                }
597
 
                if (FD_ISSET(data->buf[i].fd, &rfds)) {
598
 
                    int ret = read_fd_data(&data->buf[i]);
599
 
                    if (ret == -1 || !ret) {
600
 
                        if (ret == -1)
601
 
                            logg("!Error condition on fd %d\n",
602
 
                                 data->buf[i].fd);
603
 
                        else {
604
 
                            /* avoid SHUT_WR problem on Mac OS X */
605
 
                            int ret = send(data->buf[i].fd, &i, 0, 0);
606
 
                            if (!ret || (ret == -1 && errno == EINTR))
607
 
                                continue;
608
 
                            logg("*Client disconnected\n");
609
 
                        }
610
 
                        data->buf[i].got_newdata = -1;
611
 
                    }
612
 
                }
613
 
            }
614
 
        }
615
 
        if (retval < 0 && errno == EBADF) {
616
 
            /* unlike poll(),  select() won't tell us which FD is bad, so
617
 
             * we have to check them one by one. */
618
 
            tv.tv_sec = 0;
619
 
            tv.tv_usec = 0;
620
 
            /* with tv == 0 it doesn't check for EBADF */
621
 
            FD_ZERO(&rfds);
622
 
            for (i=0; i< data->nfds; i++) {
623
 
                if (data->buf[i].fd == -1)
624
 
                    continue;
625
 
                FD_SET(data->buf[i].fd, &rfds);
626
 
                do {
627
 
                    retval = select(data->buf[i].fd+1, &rfds, NULL, NULL, &tv);
628
 
                } while (retval == -1 && errno == EINTR);
629
 
                if (retval == -1) {
630
 
                    data->buf[i].fd = -1;
631
 
                } else {
632
 
                    FD_CLR(data->buf[i].fd, &rfds);
633
 
                }
634
 
            }
635
 
            retval = -1;
636
 
            errno = EINTR;
637
 
            continue;
638
 
        }
639
 
    } while (retval == -1 && !check_signals && errno == EINTR);
640
 
    }
641
 
#endif
642
 
 
643
 
    if (retval == -1 && errno != EINTR) {
644
 
        char err[128];
645
 
#ifdef HAVE_POLL
646
 
        logg("!poll_recv_fds: poll failed: %s\n", cli_strerror(errno, err, sizeof(err)));
647
 
#else
648
 
        logg("!poll_recv_fds: select failed: %s\n", cli_strerror(errno, err, sizeof(err)));
649
 
#endif
650
 
    }
651
 
 
652
 
    return retval;
653
 
}
654
 
 
655
 
void fds_free(struct fd_data *data)
656
 
{
657
 
    unsigned i;
658
 
    fds_lock(data);
659
 
    for (i=0;i < data->nfds;i++) {
660
 
        if (data->buf[i].buffer) {
661
 
            free(data->buf[i].buffer);
662
 
        }
663
 
    }
664
 
    if (data->buf)
665
 
        free(data->buf);
666
 
#ifdef HAVE_POLL
667
 
    if (data->poll_data)
668
 
        free(data->poll_data);
669
 
#endif
670
 
    data->buf = NULL;
671
 
    data->nfds = 0;
672
 
    fds_unlock(data);
673
 
}
674
 
 
675
 
struct detstats_s {
676
 
    char virname[128];
677
 
    char fname[128];
678
 
    char md5[33];
679
 
    unsigned int fsize;
680
 
    unsigned int time;
681
 
};
682
 
#define DETSTATS_MAX 50
683
 
static struct detstats_s detstats_data[DETSTATS_MAX];
684
 
static unsigned int detstats_idx = 0, detstats_total = 0;
685
 
 
686
 
void detstats_clear(void)
687
 
{
688
 
    pthread_mutex_lock(&detstats_lock);
689
 
    detstats_idx = detstats_total = 0;
690
 
    pthread_mutex_unlock(&detstats_lock);
691
 
}
692
 
 
693
 
void detstats_add(const char *virname, const char *fname, unsigned int fsize, const char *md5)
694
 
{
695
 
    pthread_mutex_lock(&detstats_lock);
696
 
 
697
 
    strncpy(detstats_data[detstats_idx].virname, virname, sizeof(detstats_data[detstats_idx].virname));
698
 
    detstats_data[detstats_idx].virname[sizeof(detstats_data[detstats_idx].virname) - 1] = 0;
699
 
 
700
 
    if((fname = strrchr(fname, *PATHSEP)))
701
 
        fname++;
702
 
    strncpy(detstats_data[detstats_idx].fname, (!fname || !strlen(fname)) ? "NOFNAME" : fname, sizeof(detstats_data[detstats_idx].fname));
703
 
    detstats_data[detstats_idx].fname[sizeof(detstats_data[detstats_idx].fname) - 1] = 0;
704
 
 
705
 
    strncpy(detstats_data[detstats_idx].md5, md5, sizeof(detstats_data[detstats_idx].md5));
706
 
    detstats_data[detstats_idx].md5[sizeof(detstats_data[detstats_idx].md5) - 1] = 0;
707
 
 
708
 
    detstats_data[detstats_idx].fsize = fsize;
709
 
    detstats_data[detstats_idx++].time = time(NULL);
710
 
    if(detstats_idx == DETSTATS_MAX)
711
 
        detstats_idx = 0;
712
 
    detstats_total++;
713
 
    pthread_mutex_unlock(&detstats_lock);
714
 
}
715
 
 
716
 
void detstats_print(int desc, char term)
717
 
{
718
 
        unsigned int i;
719
 
 
720
 
    pthread_mutex_lock(&detstats_lock);
721
 
    for(i = 0; i < DETSTATS_MAX && i < detstats_total; i++)
722
 
        mdprintf(desc, "%u:%s:%u:%s:%s%c", detstats_data[i].time, detstats_data[i].md5, detstats_data[i].fsize, detstats_data[i].virname, detstats_data[i].fname, term);
723
 
    pthread_mutex_unlock(&detstats_lock);
 
473
        if(n == 0)
 
474
            break;
 
475
    }
 
476
    n += boff;
 
477
    if(read_command) {
 
478
        if((n >= 1) && (buf[0] == 'n')) { /* Need to strip leading 'n' from command to attain standard command */
 
479
            --n;
 
480
            memcpy(buf, buf+1, n);
 
481
            buf[n] = '\0';
 
482
        }
 
483
        return !strncmp(buf, "FD", 2) ? -1 : n; /* an explicit FD command is invalid */
 
484
    }
 
485
    return n;
724
486
}