git-svn: trunk@2299
Nigel Horne authored on 2006/09/22 01:40:51... | ... |
@@ -1,3 +1,8 @@ |
1 |
+Thu Sep 21 17:39:29 BST 2006 (njh) |
|
2 |
+---------------------------------- |
|
3 |
+ * libclamav/mbox.c: Experimental mode now no longer uses libcurl to |
|
4 |
+ download referenced pages to be scanned |
|
5 |
+ |
|
1 | 6 |
Thu Sep 21 10:36:32 BST 2006 (njh) |
2 | 7 |
---------------------------------- |
3 | 8 |
* libclamav/mbox.c: Handle segfaults in libcurl |
... | ... |
@@ -16,7 +16,7 @@ |
16 | 16 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
17 | 17 |
* MA 02110-1301, USA. |
18 | 18 |
*/ |
19 |
-static char const rcsid[] = "$Id: mbox.c,v 1.339 2006/09/21 14:42:06 njh Exp $"; |
|
19 |
+static char const rcsid[] = "$Id: mbox.c,v 1.340 2006/09/21 16:38:33 njh Exp $"; |
|
20 | 20 |
|
21 | 21 |
#if HAVE_CONFIG_H |
22 | 22 |
#include "clamav-config.h" |
... | ... |
@@ -4214,6 +4214,408 @@ checkURLs(message *m, mbox_ctx *mctx, int* rc, int is_html) |
4214 | 4214 |
*/ |
4215 | 4215 |
#ifdef WITH_CURL |
4216 | 4216 |
|
4217 |
+#ifdef CL_EXPERIMENTAL |
|
4218 |
+/* |
|
4219 |
+ * Removing the reliance on libcurl |
|
4220 |
+ * Includes some of the freshclam hacks by Everton da Silva Marques |
|
4221 |
+ * everton.marques@gmail.com> |
|
4222 |
+ */ |
|
4223 |
+#include <netdb.h> |
|
4224 |
+#include <sys/socket.h> |
|
4225 |
+#include <netinet/in.h> |
|
4226 |
+#include <net/if.h> |
|
4227 |
+#include <arpa/inet.h> |
|
4228 |
+#include <ctype.h> |
|
4229 |
+#include <errno.h> |
|
4230 |
+#include <fcntl.h> |
|
4231 |
+#include <sys/time.h> |
|
4232 |
+#include <stdlib.h> |
|
4233 |
+ |
|
4234 |
+#ifndef timercmp |
|
4235 |
+# define timercmp(a, b, cmp) \ |
|
4236 |
+ (((a)->tv_sec == (b)->tv_sec) ? \ |
|
4237 |
+ ((a)->tv_usec cmp (b)->tv_usec) : \ |
|
4238 |
+ ((a)->tv_sec cmp (b)->tv_sec)) |
|
4239 |
+#endif /* timercmp */ |
|
4240 |
+ |
|
4241 |
+#ifndef timersub |
|
4242 |
+# define timersub(a, b, result) \ |
|
4243 |
+ do { \ |
|
4244 |
+ (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ |
|
4245 |
+ (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ |
|
4246 |
+ if ((result)->tv_usec < 0) { \ |
|
4247 |
+ --(result)->tv_sec; \ |
|
4248 |
+ (result)->tv_usec += 1000000; \ |
|
4249 |
+ } \ |
|
4250 |
+ } while (0) |
|
4251 |
+#endif /* timersub */ |
|
4252 |
+ |
|
4253 |
+static long nonblock_fcntl(int sock); |
|
4254 |
+static void restore_fcntl(int sock, long fcntl_flags); |
|
4255 |
+static int nonblock_connect(int sock, const struct sockaddr *addr, socklen_t addrlen, int secs); |
|
4256 |
+static int connect_error(int sock); |
|
4257 |
+ |
|
4258 |
+#define NONBLOCK_SELECT_MAX_FAILURES 3 |
|
4259 |
+#define NONBLOCK_MAX_BOGUS_LOOPS 10 |
|
4260 |
+static void * |
|
4261 |
+#ifdef CL_THREAD_SAFE |
|
4262 |
+getURL(void *a) |
|
4263 |
+#else |
|
4264 |
+getURL(struct arg *arg) |
|
4265 |
+#endif |
|
4266 |
+{ |
|
4267 |
+ FILE *fp; |
|
4268 |
+#ifdef CL_THREAD_SAFE |
|
4269 |
+ struct arg *arg = (struct arg *)a; |
|
4270 |
+#endif |
|
4271 |
+ const char *url = arg->url; |
|
4272 |
+ const char *dir = arg->dir; |
|
4273 |
+ const char *filename = arg->filename; |
|
4274 |
+ char fout[NAME_MAX + 1]; |
|
4275 |
+ const struct protoent *proto; |
|
4276 |
+ int sd, n; |
|
4277 |
+ struct sockaddr_in server; |
|
4278 |
+ in_addr_t ip; |
|
4279 |
+ char buf[BUFSIZ]; |
|
4280 |
+ char site[BUFSIZ]; |
|
4281 |
+ in_port_t port = 80; |
|
4282 |
+ int doingsite = 1; |
|
4283 |
+ char *ptr; |
|
4284 |
+ int flags; |
|
4285 |
+ const char *proxy; |
|
4286 |
+ |
|
4287 |
+ snprintf(fout, sizeof(fout) - 1, "%s/%s", dir, filename); |
|
4288 |
+ |
|
4289 |
+ cli_dbgmsg("Saving %s to %s\n", url, fout); |
|
4290 |
+ fp = fopen(fout, "wb"); |
|
4291 |
+ |
|
4292 |
+ if(fp == NULL) { |
|
4293 |
+ cli_errmsg("Can't open '%s' for writing", fout); |
|
4294 |
+ return NULL; |
|
4295 |
+ } |
|
4296 |
+ proxy = getenv("http_proxy"); /* FIXME: handle no_proxy */ |
|
4297 |
+ if(proxy && *proxy) { |
|
4298 |
+ cli_dbgmsg("Getting %s via %s\n", url, proxy); |
|
4299 |
+ snprintf(buf, sizeof(buf) - 1, |
|
4300 |
+ "GET /%s HTTP/1.0\nHost: %s\nUser-Agent: www.clamav.net\n\n", |
|
4301 |
+ url, site); |
|
4302 |
+ if(strncasecmp(proxy, "http://", 7) != 0) { |
|
4303 |
+ cli_warnmsg("Unsupported proxy protocol\n"); |
|
4304 |
+ fclose(fp); |
|
4305 |
+ return NULL; |
|
4306 |
+ } |
|
4307 |
+ |
|
4308 |
+ proxy += 7; |
|
4309 |
+ ptr = site; |
|
4310 |
+ while(*proxy) { |
|
4311 |
+ if(doingsite && (*proxy == ':')) { |
|
4312 |
+ port = 0; |
|
4313 |
+ while(isdigit(*++proxy)) { |
|
4314 |
+ port *= 10; |
|
4315 |
+ port += *proxy - '0'; |
|
4316 |
+ } |
|
4317 |
+ continue; |
|
4318 |
+ } |
|
4319 |
+ if(doingsite && (*proxy == '/')) { |
|
4320 |
+ doingsite = 0; |
|
4321 |
+ proxy++; |
|
4322 |
+ *ptr = '\0'; |
|
4323 |
+ break; |
|
4324 |
+ } |
|
4325 |
+ *ptr++ = *proxy++; |
|
4326 |
+ } |
|
4327 |
+ |
|
4328 |
+ memset((char *)&server, 0, sizeof(struct sockaddr_in)); |
|
4329 |
+ server.sin_family = AF_INET; |
|
4330 |
+ server.sin_port = htons(port); |
|
4331 |
+ |
|
4332 |
+ ip = inet_addr(site); |
|
4333 |
+#ifdef INADDR_NONE |
|
4334 |
+ if(ip == INADDR_NONE) { |
|
4335 |
+#else |
|
4336 |
+ if(ip == (in_addr_t)-1) { |
|
4337 |
+#endif |
|
4338 |
+ const struct hostent *h = gethostbyname(site); |
|
4339 |
+ |
|
4340 |
+ if(h == NULL) { |
|
4341 |
+ cli_dbgmsg("Unknown host %s\n", site); |
|
4342 |
+ fclose(fp); |
|
4343 |
+ return NULL; |
|
4344 |
+ } |
|
4345 |
+ |
|
4346 |
+ memcpy((char *)&ip, h->h_addr, sizeof(ip)); |
|
4347 |
+ } |
|
4348 |
+ server.sin_addr.s_addr = ip; |
|
4349 |
+ |
|
4350 |
+ proto = getprotobyname("tcp"); |
|
4351 |
+ if(proto == NULL) { |
|
4352 |
+ cli_warnmsg("Unknown prototol tcp, check /etc/protocols\n"); |
|
4353 |
+ fclose(fp); |
|
4354 |
+ return NULL; |
|
4355 |
+ } |
|
4356 |
+ if((sd = socket(AF_INET, SOCK_STREAM, proto->p_proto)) < 0) |
|
4357 |
+ return NULL; |
|
4358 |
+ flags = nonblock_fcntl(sd); |
|
4359 |
+ if(nonblock_connect(sd, (struct sockaddr *)&server, sizeof(struct sockaddr_in), 5) < 0) { |
|
4360 |
+ close(sd); |
|
4361 |
+ fclose(fp); |
|
4362 |
+ return NULL; |
|
4363 |
+ } |
|
4364 |
+ restore_fcntl(sd, flags); |
|
4365 |
+ |
|
4366 |
+ snprintf(buf, sizeof(buf) - 1, |
|
4367 |
+ "GET %s HTTP/1.0\nHost: %s\nUser-Agent: www.clamav.net\n\n", |
|
4368 |
+ url, site); |
|
4369 |
+ } else { |
|
4370 |
+ cli_dbgmsg("Getting %s\n", url); |
|
4371 |
+ |
|
4372 |
+ if(strncasecmp(url, "http://", 7) != 0) { |
|
4373 |
+ cli_warnmsg("Unsupported protocol\n"); |
|
4374 |
+ fclose(fp); |
|
4375 |
+ return NULL; |
|
4376 |
+ } |
|
4377 |
+ |
|
4378 |
+ url += 7; |
|
4379 |
+ ptr = site; |
|
4380 |
+ while(*url) { |
|
4381 |
+ if(doingsite && (*url == ':')) { |
|
4382 |
+ port = 0; |
|
4383 |
+ while(isdigit(*++url)) { |
|
4384 |
+ port *= 10; |
|
4385 |
+ port += *url - '0'; |
|
4386 |
+ } |
|
4387 |
+ continue; |
|
4388 |
+ } |
|
4389 |
+ if(doingsite && (*url == '/')) { |
|
4390 |
+ doingsite = 0; |
|
4391 |
+ url++; |
|
4392 |
+ *ptr = '\0'; |
|
4393 |
+ break; |
|
4394 |
+ } |
|
4395 |
+ *ptr++ = *url++; |
|
4396 |
+ } |
|
4397 |
+ |
|
4398 |
+ memset((char *)&server, 0, sizeof(struct sockaddr_in)); |
|
4399 |
+ server.sin_family = AF_INET; |
|
4400 |
+ server.sin_port = htons(port); |
|
4401 |
+ |
|
4402 |
+ ip = inet_addr(site); |
|
4403 |
+#ifdef INADDR_NONE |
|
4404 |
+ if(ip == INADDR_NONE) { |
|
4405 |
+#else |
|
4406 |
+ if(ip == (in_addr_t)-1) { |
|
4407 |
+#endif |
|
4408 |
+ const struct hostent *h = gethostbyname(site); |
|
4409 |
+ |
|
4410 |
+ if(h == NULL) { |
|
4411 |
+ cli_dbgmsg("Unknown host %s\n", site); |
|
4412 |
+ fclose(fp); |
|
4413 |
+ return NULL; |
|
4414 |
+ } |
|
4415 |
+ |
|
4416 |
+ memcpy((char *)&ip, h->h_addr, sizeof(ip)); |
|
4417 |
+ } |
|
4418 |
+ server.sin_addr.s_addr = ip; |
|
4419 |
+ |
|
4420 |
+ proto = getprotobyname("tcp"); |
|
4421 |
+ if(proto == NULL) { |
|
4422 |
+ cli_warnmsg("Unknown prototol tcp, check /etc/protocols\n"); |
|
4423 |
+ fclose(fp); |
|
4424 |
+ return NULL; |
|
4425 |
+ } |
|
4426 |
+ if((sd = socket(AF_INET, SOCK_STREAM, proto->p_proto)) < 0) { |
|
4427 |
+ fclose(fp); |
|
4428 |
+ return NULL; |
|
4429 |
+ } |
|
4430 |
+ flags = nonblock_fcntl(sd); |
|
4431 |
+ if(nonblock_connect(sd, (struct sockaddr *)&server, sizeof(struct sockaddr_in), 5) < 0) { |
|
4432 |
+ close(sd); |
|
4433 |
+ fclose(fp); |
|
4434 |
+ return NULL; |
|
4435 |
+ } |
|
4436 |
+ restore_fcntl(sd, flags); |
|
4437 |
+ |
|
4438 |
+ snprintf(buf, sizeof(buf) - 1, |
|
4439 |
+ "GET /%s HTTP/1.0\nHost: %s\nUser-Agent: www.clamav.net\n\n", |
|
4440 |
+ url, site); |
|
4441 |
+ } |
|
4442 |
+ |
|
4443 |
+ if(send(sd, buf, strlen(buf), 0) < 0) { |
|
4444 |
+ close(sd); |
|
4445 |
+ fclose(fp); |
|
4446 |
+ return NULL; |
|
4447 |
+ } |
|
4448 |
+ |
|
4449 |
+ shutdown(sd, SHUT_WR); |
|
4450 |
+ |
|
4451 |
+ for(;;) { |
|
4452 |
+ fd_set set; |
|
4453 |
+ struct timeval tv; |
|
4454 |
+ |
|
4455 |
+ FD_ZERO(&set); |
|
4456 |
+ FD_SET(sd, &set); |
|
4457 |
+ |
|
4458 |
+ tv.tv_sec = 30; /* FIXME: make this customisable */ |
|
4459 |
+ tv.tv_usec = 0; |
|
4460 |
+ |
|
4461 |
+ if(select(sd + 1, &set, NULL, NULL, &tv) < 0) { |
|
4462 |
+ if(errno == EINTR) |
|
4463 |
+ continue; |
|
4464 |
+ close(sd); |
|
4465 |
+ fclose(fp); |
|
4466 |
+ return NULL; |
|
4467 |
+ } |
|
4468 |
+ if(!FD_ISSET(sd, &set)) { |
|
4469 |
+ fclose(fp); |
|
4470 |
+ close(sd); |
|
4471 |
+ return NULL; |
|
4472 |
+ } |
|
4473 |
+ n = recv(sd, buf, BUFSIZ, 0); |
|
4474 |
+ if(n < 0) { |
|
4475 |
+ fclose(fp); |
|
4476 |
+ close(sd); |
|
4477 |
+ return NULL; |
|
4478 |
+ } |
|
4479 |
+ if(n == 0) |
|
4480 |
+ break; |
|
4481 |
+ if(fwrite(buf, n, 1, fp) != 1) { |
|
4482 |
+ cli_warnmsg("Error writing %d bytes to %s\n", |
|
4483 |
+ n, fout); |
|
4484 |
+ break; |
|
4485 |
+ } |
|
4486 |
+ } |
|
4487 |
+ |
|
4488 |
+ fclose(fp); |
|
4489 |
+ close(sd); |
|
4490 |
+ return NULL; |
|
4491 |
+} |
|
4492 |
+ |
|
4493 |
+static long |
|
4494 |
+nonblock_fcntl(int sock) |
|
4495 |
+{ |
|
4496 |
+ long fcntl_flags; /* Save fcntl() flags */ |
|
4497 |
+ |
|
4498 |
+ fcntl_flags = fcntl(sock, F_GETFL, 0); |
|
4499 |
+ if(fcntl_flags < 0) |
|
4500 |
+ cli_warnmsg("nonblock_fcntl: saving: fcntl(%d, F_GETFL): errno=%d: %s\n", |
|
4501 |
+ sock, errno, strerror(errno)); |
|
4502 |
+ else if(fcntl(sock, F_SETFL, fcntl_flags | O_NONBLOCK)) |
|
4503 |
+ cli_warnmsg("nonblock_fcntl: fcntl(%d, F_SETFL, O_NONBLOCK): errno=%d: %s\n", |
|
4504 |
+ sock, errno, strerror(errno)); |
|
4505 |
+ |
|
4506 |
+ return fcntl_flags; |
|
4507 |
+} |
|
4508 |
+ |
|
4509 |
+static void |
|
4510 |
+restore_fcntl(int sock, long fcntl_flags) |
|
4511 |
+{ |
|
4512 |
+ if (fcntl_flags != -1) |
|
4513 |
+ if (fcntl(sock, F_SETFL, fcntl_flags)) { |
|
4514 |
+ cli_warnmsg("restore_fcntl: restoring: fcntl(%d, F_SETFL): errno=%d: %s\n", |
|
4515 |
+ sock, errno, strerror(errno)); |
|
4516 |
+ } |
|
4517 |
+} |
|
4518 |
+ |
|
4519 |
+static int |
|
4520 |
+nonblock_connect(int sock, const struct sockaddr *addr, socklen_t addrlen, int secs) |
|
4521 |
+{ |
|
4522 |
+ /* Max. of unexpected select() failures */ |
|
4523 |
+ int select_failures = NONBLOCK_SELECT_MAX_FAILURES; |
|
4524 |
+ /* Max. of useless loops */ |
|
4525 |
+ int bogus_loops = NONBLOCK_MAX_BOGUS_LOOPS; |
|
4526 |
+ struct timeval timeout; /* When we should time out */ |
|
4527 |
+ int numfd; /* Highest fdset fd plus 1 */ |
|
4528 |
+ |
|
4529 |
+ /* Calculate into 'timeout' when we should time out */ |
|
4530 |
+ gettimeofday(&timeout, 0); |
|
4531 |
+ timeout.tv_sec += secs; |
|
4532 |
+ |
|
4533 |
+ /* Launch (possibly) non-blocking connect() request */ |
|
4534 |
+ if(connect(sock, addr, addrlen)) { |
|
4535 |
+ int e = errno; |
|
4536 |
+ cli_dbgmsg("DEBUG nonblock_connect: connect(): fd=%d errno=%d: %s\n", |
|
4537 |
+ sock, e, strerror(e)); |
|
4538 |
+ switch (e) { |
|
4539 |
+ case EALREADY: |
|
4540 |
+ case EINPROGRESS: |
|
4541 |
+ break; /* wait for connection */ |
|
4542 |
+ case EISCONN: |
|
4543 |
+ return 0; /* connected */ |
|
4544 |
+ default: |
|
4545 |
+ cli_warnmsg("nonblock_connect: connect(): fd=%d errno=%d: %s\n", |
|
4546 |
+ sock, e, strerror(e)); |
|
4547 |
+ return -1; /* failed */ |
|
4548 |
+ } |
|
4549 |
+ } else |
|
4550 |
+ return connect_error(sock); |
|
4551 |
+ |
|
4552 |
+ numfd = sock + 1; /* Highest fdset fd plus 1 */ |
|
4553 |
+ |
|
4554 |
+ for (;;) { |
|
4555 |
+ fd_set fds; |
|
4556 |
+ struct timeval now; |
|
4557 |
+ struct timeval wait; |
|
4558 |
+ int n; |
|
4559 |
+ |
|
4560 |
+ /* Force timeout if we ran out of time */ |
|
4561 |
+ gettimeofday(&now, 0); |
|
4562 |
+ if (timercmp(&now, &timeout, >)) { |
|
4563 |
+ cli_warnmsg("connect timing out (%d secs)\n", |
|
4564 |
+ secs); |
|
4565 |
+ break; /* failed */ |
|
4566 |
+ } |
|
4567 |
+ |
|
4568 |
+ /* Calculate into 'wait' how long to wait */ |
|
4569 |
+ timersub(&timeout, &now, &wait); /* wait = timeout - now */ |
|
4570 |
+ |
|
4571 |
+ /* Init fds with 'sock' as the only fd */ |
|
4572 |
+ FD_ZERO(&fds); |
|
4573 |
+ FD_SET(sock, &fds); |
|
4574 |
+ |
|
4575 |
+ n = select(numfd, 0, &fds, 0, &wait); |
|
4576 |
+ if (n < 0) { |
|
4577 |
+ cli_warnmsg("nonblock_connect: select() failure %d: errno=%d: %s\n", |
|
4578 |
+ select_failures, errno, strerror(errno)); |
|
4579 |
+ if (--select_failures >= 0) |
|
4580 |
+ continue; /* keep waiting */ |
|
4581 |
+ break; /* failed */ |
|
4582 |
+ } |
|
4583 |
+ |
|
4584 |
+ cli_dbgmsg("DEBUG nonblock_connect: select = %d\n", n); |
|
4585 |
+ |
|
4586 |
+ if (n) { |
|
4587 |
+ return connect_error(sock); |
|
4588 |
+ } |
|
4589 |
+ |
|
4590 |
+ /* Select returned, but there is no work to do... */ |
|
4591 |
+ if (--bogus_loops < 0) { |
|
4592 |
+ cli_warnmsg("nonblock_connect: giving up due to excessive bogus loops\n"); |
|
4593 |
+ break; /* failed */ |
|
4594 |
+ } |
|
4595 |
+ |
|
4596 |
+ } /* for loop: keep waiting */ |
|
4597 |
+ |
|
4598 |
+ return -1; /* failed */ |
|
4599 |
+} |
|
4600 |
+ |
|
4601 |
+static int |
|
4602 |
+connect_error(int sock) |
|
4603 |
+{ |
|
4604 |
+ int optval; |
|
4605 |
+ socklen_t optlen; |
|
4606 |
+ |
|
4607 |
+ optlen = sizeof(optval); |
|
4608 |
+ getsockopt(sock, SOL_SOCKET, SO_ERROR, &optval, &optlen); |
|
4609 |
+ |
|
4610 |
+ if(optval) |
|
4611 |
+ cli_warnmsg("connect_error: getsockopt(SO_ERROR): fd=%d error=%d: %s\n", |
|
4612 |
+ sock, optval, strerror(optval)); |
|
4613 |
+ |
|
4614 |
+ return optval ? -1 : 0; |
|
4615 |
+} |
|
4616 |
+ |
|
4617 |
+#else |
|
4618 |
+ |
|
4217 | 4619 |
static int curl_has_segfaulted; |
4218 | 4620 |
/* |
4219 | 4621 |
* Inspite of numerious bug reports, curl is still buggy :-( |
... | ... |
@@ -4352,6 +4754,7 @@ getURL(struct arg *arg) |
4352 | 4352 |
signal(SIGSEGV, oldsegv); |
4353 | 4353 |
return NULL; |
4354 | 4354 |
} |
4355 |
+#endif |
|
4355 | 4356 |
|
4356 | 4357 |
#endif |
4357 | 4358 |
#endif |