36
37
#include <sys/stat.h>
39
40
#include <sys/time.h>
40
41
#include <sys/wait.h>
45
#include <sys/param.h>
41
49
#include <sys/socket.h>
42
50
#include <sys/ioctl.h>
46
#include <sys/param.h>
49
53
#ifdef HAVE_SYS_TYPES_H
50
54
#include <sys/types.h>
52
56
#ifdef HAVE_SYS_FILIO_H
53
57
#include <sys/filio.h>
63
/* submitted by breiter@wolfereiter.com: do not use poll(2) on Interix */
61
72
#else /* HAVE_POLL_H */
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 */
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"
74
84
#include "session.h"
75
85
#include "others.h"
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"
81
void virusaction(const char *filename, const char *virname, const struct optstruct *opts)
91
void virusaction(const char *filename, const char *virname, const struct cfgstruct *copt)
83
if(optget(opts, "VirusEvent")->enabled)
93
if(cfgopt(copt, "VirusEvent")->enabled)
84
94
logg("^VirusEvent is not supported on this platform"); /* Yet */
89
#define VE_FILENAME "CLAM_VIRUSEVENT_FILENAME"
90
#define VE_VIRUSNAME "CLAM_VIRUSEVENT_VIRUSNAME"
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)
95
const struct optstruct *opt;
96
char *buffer_file, *buffer_vir, *buffer_cmd;
98
size_t i, j, v = 0, len;
101
if(!(opt = optget(opts, "VirusEvent"))->enabled)
104
env[0] = getenv("PATH");
102
struct cfgstruct *cpt;
104
if(!(cpt = cfgopt(copt, "VirusEvent"))->enabled)
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.) */
113
char *buffer, *pt, *cmd;
115
cmd = strdup(cpt->strarg);
117
if((pt = strstr(cmd, "%v"))) {
118
buffer = (char *) mcalloc(strlen(cmd) + strlen(virname) + 10, sizeof(char));
121
strcat(buffer, virname);
124
cmd = strdup(buffer);
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);
109
sprintf(buffer_file, "%s=%s", VE_FILENAME, filename);
110
env[j++] = buffer_file;
113
buffer_vir = (char *) malloc(strlen(VE_VIRUSNAME) + strlen(virname) + 2);
115
sprintf(buffer_vir, "%s=%s", VE_VIRUSNAME, virname);
116
env[j++] = buffer_vir;
121
while((pt = strstr(pt, "%v"))) {
125
len = strlen(opt->strarg);
126
buffer_cmd = (char *) calloc(len + v * strlen(virname) + 1, sizeof(char));
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);
138
buffer_cmd[j++] = opt->strarg[i];
142
pthread_mutex_lock(&virusaction_lock);
143
/* We can only call async-signal-safe functions after 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);
151
logg("!VirusEvent: fork failed.\n");
129
buffer = (char *) mcalloc(strlen(ENV_FILE) + strlen(filename) + 2, sizeof(char));
130
sprintf(buffer, "%s=%s", ENV_FILE, filename);
133
buffer = (char *) mcalloc(strlen(ENV_VIRUS) + strlen(virname) + 2, sizeof(char));
134
sprintf(buffer, "%s=%s", ENV_VIRUS, virname);
138
/* WARNING: this is uninterruptable ! */
141
/* The below is not reached but is here for completeness to remind
142
maintainers that this buffer is still allocated.. */
144
} else if (pid > 0) {
146
waitpid(pid, NULL, 0);
149
logg("!VirusAction: fork failed.\n");
152
#endif /* C_WINDOWS */
154
int poll_fds(int *fds, int nfds, int timeout_sec)
159
struct pollfd poll_1[1];
160
struct pollfd *poll_data = poll_1;
163
poll_data = mmalloc(nfds*sizeof(*poll_data));
165
logg("!poll_fds: Can't allocate memory for poll_data\n");
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;
176
if (timeout_sec > 0) {
180
retval = poll(poll_data, nfds, timeout_sec);
182
if (errno == EINTR) {
191
for (i=0; i<nfds; i++) {
192
if (poll_data[i].revents) {
208
for (i=0; i<nfds; i++) {
210
if (fds[i] >= DEFAULT_FD_SETSIZE) {
220
for (i=0; i<nfds; i++)
221
FD_SET(fds[i], &rfds);
222
tv.tv_sec = timeout_sec;
225
retval = select(maxfd+1, &rfds, NULL, NULL,
226
(timeout_sec>0 ? &tv : NULL));
228
if (errno == EINTR) {
233
if ((nfds>1) && (retval>0)) {
234
for (i=0; i<nfds; i++) {
235
if (FD_ISSET(fds[i],&rfds)) {
248
int poll_fd(int fd, int timeout_sec)
250
return poll_fds(&fd, 1, timeout_sec);
253
int is_fd_connected(int fd)
256
struct pollfd poll_data[1];
259
poll_data[0].fd = fd;
260
poll_data[0].events = POLLIN;
261
poll_data[0].revents = 0;
263
if ((count=poll(poll_data, 1, 0)) == -1) {
264
if (errno == EINTR) {
272
if (poll_data[0].revents & POLLHUP) {
275
if ((poll_data[0].revents & POLLIN) && (ioctl(fd, FIONREAD, &count) == 0)) {
288
if (fd >= DEFAULT_FD_SETSIZE) {
297
if (select(fd+1, &rfds, NULL, NULL, &tv) <= 0) {
300
if (FD_ISSET(fd, &rfds)) {
301
if (recv(fd, buff, 1, MSG_PEEK) != 1) {
159
309
/* Function: writen
160
310
Try hard to write the specified number of bytes
186
static int realloc_polldata(struct fd_data *data)
189
if (data->poll_data_nfds == data->nfds)
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");
198
data->poll_data_nfds = data->nfds;
203
int poll_fd(int fd, int timeout_sec, int check_signals)
206
struct fd_data fds = FDS_INIT(NULL);
208
if (fds_add(&fds, fd, 1, timeout_sec) == -1)
211
ret = fds_poll_recv(&fds, timeout_sec, check_signals, NULL);
212
} while (ret == -1 && errno == EINTR);
217
void fds_cleanup(struct fd_data *data)
219
struct fd_buf *newbuf;
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);
336
/* FD Support Submitted by Richard Lyons <frob-clamav*webcentral.com.au> */
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.
351
int readsock(int sockfd, char *buf, size_t size, unsigned char delim, int timeout_sec, int force_delim, int read_command)
361
#ifdef HAVE_CONTROL_IN_MSGHDR
363
#define CMSG_SPACE(len) (_CMSG_ALIGN(sizeof(struct cmsghdr)) + _CMSG_ALIGN(len))
366
#define CMSG_LEN(len) (_CMSG_ALIGN(sizeof(struct cmsghdr)) + (len))
368
struct cmsghdr *cmsg;
369
char tmp[CMSG_SPACE(sizeof(fd))];
371
time_t starttime, timenow;
376
switch(poll_fd(sockfd, (timeout_sec && ((timeout_sec-(timenow-starttime)) > 0)) ? timeout_sec-(timenow-starttime) : 0)) {
377
case 0: /* timeout */
229
data->buf[j] = data->buf[i];
234
for (i = j ; i < data->nfds; i++)
235
data->buf[i].fd = -1;
237
logg("$Number of file descriptors polled: %u fds\n", (unsigned) data->nfds);
239
newbuf = realloc(data->buf, j*sizeof(*newbuf));
243
data->buf = newbuf;/* non-fatal if shrink fails */
246
static int read_fd_data(struct fd_buf *buf)
251
if (!buf->buffer) /* listen-only socket */
254
if (buf->off >= buf->bufsize)
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
261
#ifdef HAVE_FD_PASSING
264
struct cmsghdr *cmsg;
266
unsigned char buff[CMSG_SPACE(sizeof(int))];
271
if (buf->recvfd != -1) {
272
logg("$Closing unclaimed FD: %d\n", buf->recvfd);
276
memset(&msg, 0, sizeof(msg));
277
iov[0].iov_base = buf->buffer + buf->off;
278
iov[0].iov_len = buf->bufsize - buf->off;
281
msg.msg_control = b.buff;
282
msg.msg_controllen = sizeof(b.buff);
284
n = recvmsg(buf->fd, &msg, 0);
287
if (msg.msg_flags & MSG_TRUNC) {
288
logg("^Message truncated at %d bytes\n", (int)n);
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);
296
logg("^Control message truncated, no control data received, %d bytes read"
298
"(Is SELinux/AppArmor enabled, and blocking file descriptor passing?)"
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);
314
buf->recvfd = *(int *)CMSG_DATA(cmsg);
315
logg("$Receveived a file descriptor: %d\n", buf->recvfd);
386
n = recv(sockfd, buf, size, MSG_PEEK);
388
if((n >= 1) && (buf[0] == 0)) { /* FD message */
390
iov[0].iov_base = buf;
391
iov[0].iov_len = size;
392
memset(&msg, 0, sizeof(msg));
396
#ifdef HAVE_ACCRIGHTS_IN_MSGHDR
397
msg.msg_accrights = (caddr_t)&fd;
398
msg.msg_accrightslen = sizeof(fd);
400
#ifdef HAVE_CONTROL_IN_MSGHDR
401
msg.msg_control = tmp;
402
msg.msg_controllen = sizeof(tmp);
404
#if defined(HAVE_RECVMSG) && !defined(C_OS2) && !defined(INCOMPLETE_CMSG)
405
n = recvmsg(sockfd, &msg, 0);
321
n = recv(buf->fd, buf->buffer + buf->off, buf->bufsize - buf->off,0);
329
static int buf_init(struct fd_buf *buf, int listen_only, int timeout)
332
buf->got_newdata = 0;
334
buf->mode = MODE_COMMAND;
339
buf->dumpname = NULL;
344
buf->bufsize = PATH_MAX+8;
345
/* plus extra space for a \0 so we can make sure every command is \0
347
if (!(buf->buffer = malloc(buf->bufsize + 1))) {
348
logg("!add_fd: Memory allocation failed for command buffer\n");
359
time(&buf->timeout_at);
360
buf->timeout_at += timeout;
367
int fds_add(struct fd_data *data, int fd, int listen_only, int timeout)
372
logg("!add_fd: invalid fd passed to add_fd\n");
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)
386
buf = realloc(data->buf, n*sizeof(*buf));
388
logg("!add_fd: Memory allocation failed for fd_buf\n");
393
data->buf[n-1].buffer = NULL;
394
if (buf_init(&data->buf[n-1], listen_only, timeout) < 0)
396
data->buf[n-1].fd = fd;
400
static inline void fds_lock(struct fd_data *data)
403
pthread_mutex_lock(data->buf_mutex);
406
static inline void fds_unlock(struct fd_data *data)
409
pthread_mutex_unlock(data->buf_mutex);
412
void fds_remove(struct fd_data *data, int fd)
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);
412
#ifdef HAVE_ACCRIGHTS_IN_MSGHDR
413
if(msg.msg_accrightslen != sizeof(fd))
416
#ifdef HAVE_CONTROL_IN_MSGHDR
417
cmsg = CMSG_FIRSTHDR(&msg);
420
if(cmsg->cmsg_type != SCM_RIGHTS)
422
if(cmsg->cmsg_len != CMSG_LEN(sizeof(fd)))
424
fd = *(int *)CMSG_DATA(cmsg);
428
n = snprintf(buf, size, "FD %d", fd);
429
if((size_t) n >= size)
433
if((n >= 1) && (buf[0] == 'n')) { /* Newline delimited command */
440
pdelim = memchr(buf, delim, n+boff);
442
n = recv(sockfd, buf+boff, pdelim-buf+1-boff, 0);
445
n = recv(sockfd, buf+boff, n, 0);
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.
436
/* TODO: handle ReadTimeout */
437
int fds_poll_recv(struct fd_data *data, int timeout, int check_signals, void *event)
439
unsigned fdsok = data->nfds;
442
time_t now, closest_timeout;
444
/* we must have at least one fd, the control fd! */
450
for (i=0;i < data->nfds;i++) {
451
data->buf[i].got_newdata = 0;
456
closest_timeout = now + timeout;
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) {
463
data->buf[i].got_newdata = -2;
464
/* we must return immediately from poll/select, we have a timeout! */
465
closest_timeout = now;
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);
453
n = recv(sockfd, buf+boff, pdelim-buf+1-boff, 0);
455
n = recv(sockfd, buf+boff, size-boff, 0);
474
timeout = closest_timeout - now;
478
logg("$fds_poll_recv: timeout after %d seconds\n", timeout);
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
488
if (realloc_polldata(data) == -1)
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;
504
retval = poll_with_event(data->poll_data, n, timeout, event);
506
retval = poll(data->poll_data, n, timeout);
512
/* nfds may change during poll, but not
514
for (i=0;i < data->poll_data_nfds; i++) {
516
if (data->buf[i].fd < 0)
518
if (data->buf[i].fd != data->poll_data[i].fd) {
519
/* should never happen */
520
logg("!poll_recv_fds FD mismatch\n");
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);
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))
535
if (revents & POLLIN) {
536
int ret = read_fd_data(&data->buf[i]);
537
/* Data available to be read */
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);
550
/* error on file descriptor */
551
logg("^Error condition on fd %d\n",
552
data->poll_data[i].fd);
554
data->buf[i].got_newdata = -1;
460
switch(poll_fd(sockfd, ((timeout_sec-(timenow-starttime)) > 0) ? timeout_sec-(timenow-starttime) : 0)) {
461
case 0: /* timeout */
560
} while (retval == -1 && !check_signals && errno == EINTR);
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);
574
maxfd = MAX(maxfd, fd);
579
for(i=0;i < data->nfds;i++) {
580
int fd = data->buf[i].fd;
588
retval = select(maxfd+1, &rfds, NULL, NULL, timeout >= 0 ? &tv : NULL);
592
for (i=0; i < data->nfds; i++) {
593
if (data->buf[i].fd < 0) {
597
if (FD_ISSET(data->buf[i].fd, &rfds)) {
598
int ret = read_fd_data(&data->buf[i]);
599
if (ret == -1 || !ret) {
601
logg("!Error condition on fd %d\n",
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))
608
logg("*Client disconnected\n");
610
data->buf[i].got_newdata = -1;
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. */
620
/* with tv == 0 it doesn't check for EBADF */
622
for (i=0; i< data->nfds; i++) {
623
if (data->buf[i].fd == -1)
625
FD_SET(data->buf[i].fd, &rfds);
627
retval = select(data->buf[i].fd+1, &rfds, NULL, NULL, &tv);
628
} while (retval == -1 && errno == EINTR);
630
data->buf[i].fd = -1;
632
FD_CLR(data->buf[i].fd, &rfds);
639
} while (retval == -1 && !check_signals && errno == EINTR);
643
if (retval == -1 && errno != EINTR) {
646
logg("!poll_recv_fds: poll failed: %s\n", cli_strerror(errno, err, sizeof(err)));
648
logg("!poll_recv_fds: select failed: %s\n", cli_strerror(errno, err, sizeof(err)));
655
void fds_free(struct fd_data *data)
659
for (i=0;i < data->nfds;i++) {
660
if (data->buf[i].buffer) {
661
free(data->buf[i].buffer);
668
free(data->poll_data);
682
#define DETSTATS_MAX 50
683
static struct detstats_s detstats_data[DETSTATS_MAX];
684
static unsigned int detstats_idx = 0, detstats_total = 0;
686
void detstats_clear(void)
688
pthread_mutex_lock(&detstats_lock);
689
detstats_idx = detstats_total = 0;
690
pthread_mutex_unlock(&detstats_lock);
693
void detstats_add(const char *virname, const char *fname, unsigned int fsize, const char *md5)
695
pthread_mutex_lock(&detstats_lock);
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;
700
if((fname = strrchr(fname, *PATHSEP)))
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;
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;
708
detstats_data[detstats_idx].fsize = fsize;
709
detstats_data[detstats_idx++].time = time(NULL);
710
if(detstats_idx == DETSTATS_MAX)
713
pthread_mutex_unlock(&detstats_lock);
716
void detstats_print(int desc, char term)
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);
478
if((n >= 1) && (buf[0] == 'n')) { /* Need to strip leading 'n' from command to attain standard command */
480
memcpy(buf, buf+1, n);
483
return !strncmp(buf, "FD", 2) ? -1 : n; /* an explicit FD command is invalid */