1 /*
2 * Copyright 2007 Niels Provos <provos@citi.umich.edu>
3 * All rights reserved.
4 */
5
6 #include <sys/types.h>
7
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif
11
12 #include <sys/time.h>
13 #include <sys/param.h>
14 #include <sys/socket.h>
15 #include <sys/queue.h>
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include <signal.h>
20 #include <err.h>
21 #include <fcntl.h>
22 #include <unistd.h>
23 #include <assert.h>
24 #include <errno.h>
25
26 #include <event.h>
27
28 #include "virus.h"
29 #include "spybye.gen.h"
30
31 ssize_t atomicio(ssize_t (*f) (), int fd, void *_s, size_t n);
32
33 static struct cl_node *engine = NULL;
34 static struct virusq children;
35 static struct scanctxq scans;
36
37 static struct virus_child *virus_child_new();
38
39 #ifndef HAVE_CLAMAV
virus_init(void)40 int virus_init(void) {
41 return (-1);
42 }
43 static const char *
clamav_scan_buffer(char * data,int length)44 clamav_scan_buffer(char *data, int length) {
45 return "error";
46 }
47 #else
48 #include <clamav.h>
49
50 /*
51 * initalize the virus scanning system; this really mixes clamav and our
52 * generic frame work but that does not matter for now
53 */
54
55 int
virus_init(void)56 virus_init(void)
57 {
58 int res = 0, i;
59 unsigned int sigs = 0;
60
61 res = cl_loaddbdir(cl_retdbdir(), &engine, &sigs);
62 if (res) {
63 fprintf(stderr, "[VIRUS] Failed to load clamav: %s\n",
64 cl_strerror(res));
65 return (-1);
66 }
67
68 res = cl_build(engine);
69 if (res) {
70 fprintf(stderr, "[VIRUS] Failed to build engine: %s\n",
71 cl_strerror(res));
72 return (-1);
73 }
74
75 fprintf(stderr, "[VIRUS] Loaded %d signatures\n", sigs);
76
77 TAILQ_INIT(&children);
78 TAILQ_INIT(&scans);
79
80 for(i = 0; i < NUM_VIRUS_CHILDREN; ++i)
81 virus_child_new();
82
83 return (0);
84 }
85
86 static const char *
clamav_scan_buffer(char * data,int length)87 clamav_scan_buffer(char *data, int length)
88 {
89 const char *virname;
90 struct cl_limits limits;
91 int res;
92
93 /* somewhat stupid but here we go */
94 FILE *fp = tmpfile();
95 if (fp == NULL)
96 return ("error");
97
98 if (atomicio(write, fileno(fp), data, length) != length) {
99 fclose(fp);
100 return ("error");
101 }
102 rewind(fp);
103
104 memset(&limits, 0, sizeof(limits));
105 limits.maxfiles = 1000;
106 limits.maxfilesize = 10 * 1048576;
107 limits.maxreclevel = 5;
108 #ifdef HAVE_CLLIMITS_MAXMAILREC
109 limits.maxmailrec = 64;
110 #endif
111 limits.maxratio = 200;
112
113 res = cl_scandesc(fileno(fp), &virname, NULL, engine,
114 &limits, CL_SCAN_STDOPT);
115 fclose(fp);
116
117 if (res == CL_VIRUS)
118 return (virname);
119 else if (res == CL_CLEAN)
120 return ("clean");
121
122 return ("error");
123 }
124 #endif
125
126 /* happens in the child */
127
128 static void
virus_process(int fd,struct virusscan * vs)129 virus_process(int fd, struct virusscan *vs)
130 {
131 struct virusresult *vr;
132 struct evbuffer *data;
133 u_int8_t *buffer;
134 u_int32_t buflen;
135 u_int8_t *context;
136 u_int32_t conlen;
137 const char *result;
138 int res;
139
140 EVTAG_GET(vs, buffer, &buffer, &buflen);
141 EVTAG_GET(vs, context, &context, &conlen);
142
143 result = clamav_scan_buffer((char *)buffer, buflen);
144 fprintf(stderr, "[VIRUS] Scanned %d bytes; result: %s\n",
145 buflen, result);
146
147 vr = virusresult_new();
148 assert(vr != NULL);
149 EVTAG_ASSIGN(vr, result, result);
150 EVTAG_ASSIGN(vr, context, context, conlen);
151
152 data = evbuffer_new();
153 assert(data != NULL);
154 evtag_marshal_virusresult(data, VIRUSRESULT_TAG, vr);
155 virusresult_free(vr);
156
157 res = atomicio(write, fd, EVBUFFER_DATA(data), EVBUFFER_LENGTH(data));
158 if (res != EVBUFFER_LENGTH(data)) {
159 fprintf(stderr, "[VIRUS] Write of results failed: %ld got %d\n",
160 EVBUFFER_LENGTH(data), res);
161 exit(1);
162 }
163
164 evbuffer_free(data);
165 }
166
167 static void
virus_child_processing(int fd)168 virus_child_processing(int fd)
169 {
170 struct evbuffer *data = evbuffer_new();
171 assert(data != NULL);
172
173 do {
174 u_int32_t length;
175
176 int res = evbuffer_read(data, fd, -1);
177 if (res == 0)
178 break;
179 if (res == -1) {
180 if (errno == EINTR || errno == EAGAIN)
181 continue;
182 break;
183 }
184
185 while (evtag_peek_length(data, &length) != -1) {
186 struct virusscan *vs;
187
188 if (EVBUFFER_LENGTH(data) < length)
189 break;
190
191 if ((vs = virusscan_new()) == NULL)
192 err(1, "malloc");
193 if (evtag_unmarshal_virusscan(
194 data, VIRUSSCAN_TAG, vs) == -1) {
195 fprintf(stderr, "[VIRUS] Corrupt message\n");
196 exit(1);
197 }
198
199 /* okay - do something here */
200 virus_process(fd, vs);
201
202 virusscan_free(vs);
203 }
204 } while (1);
205 }
206
207 static void
virus_result(struct virusresult * vr)208 virus_result(struct virusresult *vr)
209 {
210 struct scanctx *ctx;
211 struct scanctx *wanted;
212 u_char *buf;
213 u_int buflen;
214 char *result;
215
216 EVTAG_GET(vr, result, &result);
217 EVTAG_GET(vr, context, &buf, &buflen);
218 assert(buflen == sizeof(wanted));
219 memcpy(&wanted, buf, buflen);
220
221 TAILQ_FOREACH(ctx, &scans, next) {
222 if ((void *)ctx == (void *)wanted)
223 break;
224 }
225
226 if ((void *)ctx != (void *)wanted)
227 return;
228
229 TAILQ_REMOVE(&scans, ctx, next);
230
231 (*ctx->cb)(result, ctx->cb_arg);
232
233 free(ctx);
234 }
235
236 /* called if we can read scan results */
237
238 static void
virus_readcb(struct bufferevent * bev,void * arg)239 virus_readcb(struct bufferevent *bev, void *arg)
240 {
241 u_int32_t length;
242 while (evtag_peek_length(bev->input, &length) != -1) {
243 struct virusresult *vr;
244
245 if (EVBUFFER_LENGTH(bev->input) < length)
246 break;
247
248 if ((vr = virusresult_new()) == NULL)
249 err(1, "malloc");
250 if (evtag_unmarshal_virusresult(
251 bev->input, VIRUSRESULT_TAG, vr) == -1) {
252 /* this really means that we need to kill the child */
253 fprintf(stderr, "[VIRUS] Corrupt message\n");
254 exit(1);
255 }
256
257 /* okay - do something here */
258 virus_result(vr);
259
260 virusresult_free(vr);
261 }
262 }
263
264 /* called if we can write more data */
265
266 static void
virus_writecb(struct bufferevent * bev,void * arg)267 virus_writecb(struct bufferevent *bev, void *arg)
268 {
269 bufferevent_disable(bev, EV_WRITE);
270 }
271
272 /* let's hope we don't get any errors */
273
274 static void
virus_errorcb(struct bufferevent * bev,short what,void * arg)275 virus_errorcb(struct bufferevent *bev, short what, void *arg)
276 {
277 /* this means that we need to kill the child */
278 }
279
280 static struct virus_child *
virus_child_new()281 virus_child_new()
282 {
283 struct virus_child *child;
284 int pair[2];
285
286 if ((child = calloc(1, sizeof(struct virus_child))) == NULL)
287 err(1, "calloc");
288
289 if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1)
290 err(1, "socketpair");
291
292 /* should make the system automatically reap child processes */
293 if (signal(SIGCHLD, SIG_IGN) == SIG_ERR)
294 err(1, "signal");
295
296 if ((child->pid = fork()) == -1)
297 err(1, "fork");
298
299 if (child->pid == 0) {
300 /* running in the child */
301 close(pair[0]);
302 virus_child_processing(pair[1]);
303 exit(0);
304 }
305
306 close(pair[1]);
307 child->fd = pair[0];
308 child->bev = bufferevent_new(child->fd,
309 virus_readcb, virus_writecb, virus_errorcb,
310 child);
311 if (child->bev == NULL)
312 err(1, "bufferevent_new");
313
314 TAILQ_INSERT_TAIL(&children, child, next);
315
316 bufferevent_enable(child->bev, EV_READ);
317
318 return (child);
319 }
320
321 /*
322 * send something to our children; when the scan is done the specified
323 * callback is going to be executed.
324 */
325
326 void
virus_scan_buffer(char * buffer,size_t buflen,void (* cb)(const char *,void *),void * cb_arg)327 virus_scan_buffer(char *buffer, size_t buflen,
328 void (*cb)(const char *, void *), void *cb_arg)
329 {
330 struct scanctx *ctx = calloc(1, sizeof(struct scanctx));
331 struct virusscan *vs = virusscan_new();
332 struct evbuffer *data = evbuffer_new();
333 struct virus_child *child;
334 assert(ctx != NULL);
335 assert(vs != NULL);
336 assert(data != NULL);
337
338 ctx->cb = cb;
339 ctx->cb_arg = cb_arg;
340
341 TAILQ_INSERT_TAIL(&scans, ctx, next);
342
343 /* okay now prepare the actual scan job */
344 EVTAG_ASSIGN(vs, buffer, (u_char *)buffer, buflen);
345 EVTAG_ASSIGN(vs, context, (u_char *)&ctx, sizeof(ctx));
346
347 /* weeh - double copy for our convenience */
348 evtag_marshal_virusscan(data, VIRUSSCAN_TAG, vs);
349
350 virusscan_free(vs);
351
352 /* get the first available child */
353 child = TAILQ_FIRST(&children);
354 assert(child != NULL);
355 TAILQ_REMOVE(&children, child, next);
356 TAILQ_INSERT_TAIL(&children, child, next);
357
358 bufferevent_write_buffer(child->bev, data);
359 bufferevent_enable(child->bev, EV_WRITE);
360 evbuffer_free(data);
361 }
362