PageRenderTime 69ms CodeModel.GetById 17ms RepoModel.GetById 2ms app.codeStats 0ms

/clamav-0.97.5/freshclam/manager.c

#
C | 2446 lines | 1997 code | 323 blank | 126 comment | 631 complexity | 2cfdf99bf35e52c9b6e526790e60947d MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. * Copyright (C) 2002 - 2006 Tomasz Kojm <tkojm@clamav.net>
  3. * HTTP/1.1 compliance by Arkadiusz Miskiewicz <misiek@pld.org.pl>
  4. * Proxy support by Nigel Horne <njh@bandsman.co.uk>
  5. * Proxy authorization support by Gernot Tenchio <g.tenchio@telco-tech.de>
  6. * (uses fmt_base64() from libowfat (http://www.fefe.de))
  7. * CDIFF code (C) 2006 Sensory Networks, Inc.
  8. *
  9. * This program is free software; you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License as published by
  11. * the Free Software Foundation; either version 2 of the License, or
  12. * (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  22. * MA 02110-1301, USA.
  23. */
  24. #if HAVE_CONFIG_H
  25. #include "clamav-config.h"
  26. #endif
  27. /* for strptime, it is POSIX, but defining _XOPEN_SOURCE to 600
  28. * fails on Solaris because it would require a c99 compiler,
  29. * 500 fails completely on Solaris, and FreeBSD, and w/o _XOPEN_SOURCE
  30. * strptime is not defined on Linux */
  31. #define _GNU_SOURCE
  32. #define __EXTENSIONS
  33. #include <stdio.h>
  34. #include <stdlib.h>
  35. #ifdef HAVE_UNISTD_H
  36. #include <unistd.h>
  37. #endif
  38. #include <string.h>
  39. #ifdef HAVE_STRINGS_H
  40. #include <strings.h>
  41. #endif
  42. #include <ctype.h>
  43. #ifndef _WIN32
  44. #include <netinet/in.h>
  45. #include <netdb.h>
  46. #include <arpa/inet.h>
  47. #include <sys/socket.h>
  48. #include <sys/time.h>
  49. #endif
  50. #include <sys/types.h>
  51. #include <time.h>
  52. #include <fcntl.h>
  53. #ifndef _WIN32
  54. #include <sys/wait.h>
  55. #endif
  56. #include <sys/stat.h>
  57. #include <dirent.h>
  58. #include <errno.h>
  59. #include <zlib.h>
  60. #include "target.h"
  61. #include "manager.h"
  62. #include "notify.h"
  63. #include "dns.h"
  64. #include "execute.h"
  65. #include "nonblock.h"
  66. #include "mirman.h"
  67. #include "shared/optparser.h"
  68. #include "shared/output.h"
  69. #include "shared/misc.h"
  70. #include "shared/cdiff.h"
  71. #include "shared/tar.h"
  72. #include "shared/clamdcom.h"
  73. #include "libclamav/clamav.h"
  74. #include "libclamav/others.h"
  75. #include "libclamav/str.h"
  76. #include "libclamav/cvd.h"
  77. #include "libclamav/regex_list.h"
  78. extern char updtmpdir[512], dbdir[512];
  79. #define CHDIR_ERR(x) \
  80. if(chdir(x) == -1) \
  81. logg("!Can't chdir to %s\n", x);
  82. #ifndef HAVE_GETADDRINFO
  83. static const char *ghbn_err(int err) /* hstrerror() */
  84. {
  85. switch(err) {
  86. case HOST_NOT_FOUND:
  87. return "Host not found";
  88. case NO_DATA:
  89. return "No IP address";
  90. case NO_RECOVERY:
  91. return "Unrecoverable DNS error";
  92. case TRY_AGAIN:
  93. return "Temporary DNS error";
  94. default:
  95. return "Unknown error";
  96. }
  97. }
  98. #endif
  99. static int getclientsock(const char *localip, int prot)
  100. {
  101. int socketfd = -1;
  102. #ifdef SUPPORT_IPv6
  103. if(prot == AF_INET6)
  104. socketfd = socket(AF_INET6, SOCK_STREAM, 0);
  105. else
  106. #endif
  107. socketfd = socket(AF_INET, SOCK_STREAM, 0);
  108. if(socketfd < 0) {
  109. logg("!Can't create new socket\n");
  110. return -1;
  111. }
  112. if(localip) {
  113. #ifdef HAVE_GETADDRINFO
  114. struct addrinfo *res;
  115. int ret;
  116. ret = getaddrinfo(localip, NULL, NULL, &res);
  117. if(ret) {
  118. logg("!Could not resolve local ip address '%s': %s\n", localip, gai_strerror(ret));
  119. logg("^Using standard local ip address and port for fetching.\n");
  120. } else {
  121. char ipaddr[46];
  122. if(bind(socketfd, res->ai_addr, res->ai_addrlen) != 0) {
  123. logg("!Could not bind to local ip address '%s': %s\n", localip, strerror(errno));
  124. logg("^Using default client ip.\n");
  125. } else {
  126. void *addr;
  127. #ifdef SUPPORT_IPv6
  128. if(res->ai_family == AF_INET6)
  129. addr = &((struct sockaddr_in6 *) res->ai_addr)->sin6_addr;
  130. else
  131. #endif
  132. addr = &((struct sockaddr_in *) res->ai_addr)->sin_addr;
  133. if(inet_ntop(res->ai_family, addr, ipaddr, sizeof(ipaddr)))
  134. logg("*Using ip '%s' for fetching.\n", ipaddr);
  135. }
  136. freeaddrinfo(res);
  137. }
  138. #else /* IPv4 */
  139. struct hostent *he;
  140. if(!(he = gethostbyname(localip))) {
  141. logg("!Could not resolve local ip address '%s': %s\n", localip, ghbn_err(h_errno));
  142. logg("^Using standard local ip address and port for fetching.\n");
  143. } else {
  144. struct sockaddr_in client;
  145. unsigned char *ia;
  146. char ipaddr[16];
  147. memset((char *) &client, 0, sizeof(client));
  148. client.sin_family = AF_INET;
  149. client.sin_addr = *(struct in_addr *) he->h_addr_list[0];
  150. if(bind(socketfd, (struct sockaddr *) &client, sizeof(struct sockaddr_in)) != 0) {
  151. logg("!Could not bind to local ip address '%s': %s\n", localip, strerror(errno));
  152. logg("^Using default client ip.\n");
  153. } else {
  154. ia = (unsigned char *) he->h_addr_list[0];
  155. sprintf(ipaddr, "%u.%u.%u.%u", ia[0], ia[1], ia[2], ia[3]);
  156. logg("*Using ip '%s' for fetching.\n", ipaddr);
  157. }
  158. }
  159. #endif
  160. }
  161. return socketfd;
  162. }
  163. #ifdef HAVE_GETADDRINFO
  164. static int qcompare(const void *a, const void *b)
  165. {
  166. return (*(const struct addrinfo **) a)->ai_flags - (*(const struct addrinfo **) b)->ai_flags;
  167. }
  168. #endif
  169. static int wwwconnect(const char *server, const char *proxy, int pport, char *ip, const char *localip, int ctimeout, struct mirdat *mdat, int logerr, unsigned int can_whitelist)
  170. {
  171. int socketfd, port, ret;
  172. unsigned int ips = 0, ignored = 0, i;
  173. #ifdef HAVE_GETADDRINFO
  174. struct addrinfo hints, *res = NULL, *rp, *loadbal_rp = NULL, *addrs[128];
  175. char port_s[6], loadbal_ipaddr[46];
  176. uint32_t loadbal = 1, minsucc = 0xffffffff, minfail = 0xffffffff, addrnum = 0;
  177. int ipv4start = -1, ipv4end = -1;
  178. struct mirdat_ip *md;
  179. #else
  180. struct sockaddr_in name;
  181. struct hostent *host;
  182. unsigned char *ia;
  183. #endif
  184. char ipaddr[46];
  185. const char *hostpt;
  186. if(ip)
  187. strcpy(ip, "UNKNOWN");
  188. if(proxy) {
  189. hostpt = proxy;
  190. if(!(port = pport)) {
  191. const struct servent *webcache = getservbyname("webcache", "TCP");
  192. if(webcache)
  193. port = ntohs(webcache->s_port);
  194. else
  195. port = 8080;
  196. endservent();
  197. }
  198. } else {
  199. hostpt = server;
  200. port = 80;
  201. }
  202. #ifdef HAVE_GETADDRINFO
  203. memset(&hints, 0, sizeof(hints));
  204. #ifdef SUPPORT_IPv6
  205. hints.ai_family = AF_UNSPEC;
  206. #else
  207. hints.ai_family = AF_INET;
  208. #endif
  209. hints.ai_socktype = SOCK_STREAM;
  210. snprintf(port_s, sizeof(port_s), "%d", port);
  211. port_s[sizeof(port_s) - 1] = 0;
  212. ret = getaddrinfo(hostpt, port_s, &hints, &res);
  213. if(ret) {
  214. logg("%cCan't get information about %s: %s\n", logerr ? '!' : '^', hostpt, gai_strerror(ret));
  215. return -1;
  216. }
  217. for(rp = res; rp && addrnum < 128; rp = rp->ai_next) {
  218. rp->ai_flags = cli_rndnum(1024);
  219. addrs[addrnum] = rp;
  220. if(rp->ai_family == AF_INET) {
  221. if(ipv4start == -1)
  222. ipv4start = addrnum;
  223. } else if(ipv4end == -1 && ipv4start != -1) {
  224. ipv4end = addrnum - 1;
  225. }
  226. if(!rp->ai_next && ipv4end == -1)
  227. ipv4end = addrnum;
  228. addrnum++;
  229. }
  230. if(ipv4end != -1 && ipv4start != -1 && ipv4end - ipv4start + 1 > 1)
  231. qsort(&addrs[ipv4start], ipv4end - ipv4start + 1, sizeof(struct addrinfo *), qcompare);
  232. for(i = 0; i < addrnum; ) {
  233. void *addr;
  234. rp = addrs[i];
  235. ips++;
  236. #ifdef SUPPORT_IPv6
  237. if(rp->ai_family == AF_INET6)
  238. addr = &((struct sockaddr_in6 *) rp->ai_addr)->sin6_addr;
  239. else
  240. #endif
  241. addr = &((struct sockaddr_in *) rp->ai_addr)->sin_addr;
  242. if(!inet_ntop(rp->ai_family, addr, ipaddr, sizeof(ipaddr))) {
  243. logg("%cinet_ntop() failed\n", logerr ? '!' : '^');
  244. freeaddrinfo(res);
  245. return -1;
  246. }
  247. if(mdat && (ret = mirman_check(addr, rp->ai_family, mdat, &md))) {
  248. if(ret == 1)
  249. logg("*Ignoring mirror %s (due to previous errors)\n", ipaddr);
  250. else
  251. logg("*Ignoring mirror %s (has connected too many times with an outdated version)\n", ipaddr);
  252. ignored++;
  253. if(!loadbal || i + 1 < addrnum) {
  254. i++;
  255. continue;
  256. }
  257. }
  258. if(mdat && loadbal) {
  259. if(!ret) {
  260. if(!md) {
  261. loadbal_rp = rp;
  262. strncpy(loadbal_ipaddr, ipaddr, sizeof(loadbal_ipaddr));
  263. } else {
  264. if(md->succ <= minsucc && md->fail <= minfail) {
  265. minsucc = md->succ;
  266. minfail = md->fail;
  267. loadbal_rp = rp;
  268. strncpy(loadbal_ipaddr, ipaddr, sizeof(loadbal_ipaddr));
  269. }
  270. if(i + 1 < addrnum) {
  271. i++;
  272. continue;
  273. }
  274. }
  275. }
  276. if(!loadbal_rp) {
  277. if(i + 1 == addrnum) {
  278. loadbal = 0;
  279. i = 0;
  280. }
  281. continue;
  282. }
  283. rp = loadbal_rp;
  284. strncpy(ipaddr, loadbal_ipaddr, sizeof(ipaddr));
  285. #ifdef SUPPORT_IPv6
  286. if(rp->ai_family == AF_INET6)
  287. addr = &((struct sockaddr_in6 *) rp->ai_addr)->sin6_addr;
  288. else
  289. #endif
  290. addr = &((struct sockaddr_in *) rp->ai_addr)->sin_addr;
  291. } else if(loadbal_rp == rp) {
  292. i++;
  293. continue;
  294. }
  295. if(ip)
  296. strcpy(ip, ipaddr);
  297. if(rp != loadbal_rp && rp != addrs[0])
  298. logg("Trying host %s (%s)...\n", hostpt, ipaddr);
  299. socketfd = getclientsock(localip, rp->ai_family);
  300. if(socketfd < 0) {
  301. freeaddrinfo(res);
  302. return -1;
  303. }
  304. #ifdef SO_ERROR
  305. if(wait_connect(socketfd, rp->ai_addr, rp->ai_addrlen, ctimeout) == -1) {
  306. #else
  307. if(connect(socketfd, rp->ai_addr, rp->ai_addrlen) == -1) {
  308. #endif
  309. logg("Can't connect to port %d of host %s (IP: %s)\n", port, hostpt, ipaddr);
  310. closesocket(socketfd);
  311. if(loadbal) {
  312. loadbal = 0;
  313. i = 0;
  314. } else i++;
  315. continue;
  316. } else {
  317. if(mdat) {
  318. if(rp->ai_family == AF_INET)
  319. mdat->currip[0] = *((uint32_t *) addr);
  320. else
  321. memcpy(mdat->currip, addr, 4 * sizeof(uint32_t));
  322. mdat->af = rp->ai_family;
  323. }
  324. freeaddrinfo(res);
  325. return socketfd;
  326. }
  327. i++;
  328. }
  329. freeaddrinfo(res);
  330. #else /* IPv4 */
  331. if((host = gethostbyname(hostpt)) == NULL) {
  332. logg("%cCan't get information about %s: %s\n", logerr ? '!' : '^', hostpt, ghbn_err(h_errno));
  333. return -1;
  334. }
  335. for(i = 0; host->h_addr_list[i] != 0; i++) {
  336. /* this dirty hack comes from pink - Nosuid TCP/IP ping 1.6 */
  337. ia = (unsigned char *) host->h_addr_list[i];
  338. sprintf(ipaddr, "%u.%u.%u.%u", ia[0], ia[1], ia[2], ia[3]);
  339. ips++;
  340. if(mdat && (ret = mirman_check(&((struct in_addr *) ia)->s_addr, AF_INET, mdat, NULL))) {
  341. if(ret == 1)
  342. logg("*Ignoring mirror %s (due to previous errors)\n", ipaddr);
  343. else
  344. logg("*Ignoring mirror %s (has connected too many times with an outdated version)\n", ipaddr);
  345. ignored++;
  346. continue;
  347. }
  348. if(ip)
  349. strcpy(ip, ipaddr);
  350. if(i > 0)
  351. logg("Trying host %s (%s)...\n", hostpt, ipaddr);
  352. memset ((char *) &name, 0, sizeof(name));
  353. name.sin_family = AF_INET;
  354. name.sin_addr = *((struct in_addr *) host->h_addr_list[i]);
  355. name.sin_port = htons(port);
  356. socketfd = getclientsock(localip, AF_INET);
  357. if(socketfd < 0)
  358. return -1;
  359. #ifdef SO_ERROR
  360. if(wait_connect(socketfd, (struct sockaddr *) &name, sizeof(struct sockaddr_in), ctimeout) == -1) {
  361. #else
  362. if(connect(socketfd, (struct sockaddr *) &name, sizeof(struct sockaddr_in)) == -1) {
  363. #endif
  364. logg("Can't connect to port %d of host %s (IP: %s)\n", port, hostpt, ipaddr);
  365. closesocket(socketfd);
  366. continue;
  367. } else {
  368. if(mdat) {
  369. mdat->currip[0] = ((struct in_addr *) ia)->s_addr;
  370. mdat->af = AF_INET;
  371. }
  372. return socketfd;
  373. }
  374. }
  375. #endif
  376. if(mdat && can_whitelist && ips && (ips == ignored))
  377. mirman_whitelist(mdat, 1);
  378. return -2;
  379. }
  380. /*
  381. static const char *readblineraw(int fd, char *buf, int bufsize, int filesize, int *bread)
  382. {
  383. char *pt;
  384. int ret, end;
  385. if(!*bread) {
  386. if(bufsize < filesize)
  387. lseek(fd, 1 - bufsize, SEEK_END);
  388. *bread = read(fd, buf, bufsize - 1);
  389. if(!*bread || *bread == -1)
  390. return NULL;
  391. buf[*bread] = 0;
  392. }
  393. pt = strrchr(buf, '\n');
  394. if(!pt)
  395. return NULL;
  396. *pt = 0;
  397. pt = strrchr(buf, '\n');
  398. if(pt) {
  399. return ++pt;
  400. } else if(*bread == filesize) {
  401. return buf;
  402. } else {
  403. *bread -= strlen(buf) + 1;
  404. end = filesize - *bread;
  405. if(end < bufsize) {
  406. if((ret = lseek(fd, 0, SEEK_SET)) != -1)
  407. ret = read(fd, buf, end);
  408. } else {
  409. if((ret = lseek(fd, end - bufsize + 1, SEEK_SET)) != -1)
  410. ret = read(fd, buf, bufsize - 1);
  411. }
  412. if(!ret || ret == -1)
  413. return NULL;
  414. buf[ret] = 0;
  415. *bread += ret;
  416. pt = strrchr(buf, '\n');
  417. if(!pt)
  418. return buf;
  419. *pt = 0;
  420. pt = strrchr(buf, '\n');
  421. if(pt)
  422. return ++pt;
  423. else if(strlen(buf))
  424. return buf;
  425. else
  426. return NULL;
  427. }
  428. }
  429. static const char *readbline(int fd, char *buf, int bufsize, int filesize, int *bread)
  430. {
  431. const char *line = readblineraw(fd, buf, bufsize, filesize, bread);
  432. if(line)
  433. cli_chomp(buf + (line - buf));
  434. return line;
  435. }
  436. */
  437. static unsigned int fmt_base64(char *dest, const char *src, unsigned int len)
  438. {
  439. unsigned short bits = 0,temp = 0;
  440. unsigned long written = 0;
  441. unsigned int i;
  442. const char base64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
  443. for(i = 0; i < len; i++) {
  444. temp <<= 8;
  445. temp += src[i];
  446. bits += 8;
  447. while(bits > 6) {
  448. dest[written] = base64[((temp >> (bits - 6)) & 63)];
  449. written++;
  450. bits -= 6;
  451. }
  452. }
  453. if(bits) {
  454. temp <<= (6 - bits);
  455. dest[written] = base64[temp & 63];
  456. written++;
  457. }
  458. while(written & 3) {
  459. dest[written] = '=';
  460. written++;
  461. }
  462. return written;
  463. }
  464. static char *proxyauth(const char *user, const char *pass)
  465. {
  466. int len;
  467. char *buf, *userpass, *auth;
  468. userpass = malloc(strlen(user) + strlen(pass) + 2);
  469. if(!userpass) {
  470. logg("!proxyauth: Can't allocate memory for 'userpass'\n");
  471. return NULL;
  472. }
  473. sprintf(userpass, "%s:%s", user, pass);
  474. buf = malloc((strlen(pass) + strlen(user)) * 2 + 4);
  475. if(!buf) {
  476. logg("!proxyauth: Can't allocate memory for 'buf'\n");
  477. free(userpass);
  478. return NULL;
  479. }
  480. len = fmt_base64(buf, userpass, strlen(userpass));
  481. free(userpass);
  482. buf[len] = '\0';
  483. auth = malloc(strlen(buf) + 30);
  484. if(!auth) {
  485. free(buf);
  486. logg("!proxyauth: Can't allocate memory for 'authorization'\n");
  487. return NULL;
  488. }
  489. sprintf(auth, "Proxy-Authorization: Basic %s\r\n", buf);
  490. free(buf);
  491. return auth;
  492. }
  493. #if BUILD_CLAMD
  494. int submitstats(const char *clamdcfg, const struct optstruct *opts)
  495. {
  496. int sd, clamsockd, bread, cnt, ret;
  497. char post[SUBMIT_MIN_ENTRIES * 256 + 512];
  498. char query[SUBMIT_MIN_ENTRIES * 256];
  499. char uastr[128], *line;
  500. char *pt, *auth = NULL;
  501. const char *country = NULL, *user, *proxy = NULL, *hostid = NULL;
  502. const struct optstruct *opt;
  503. unsigned int qcnt, entries, submitted = 0, permfail = 0, port = 0;
  504. struct RCVLN rcv;
  505. const char *tokens[5];
  506. if((opt = optget(opts, "DetectionStatsCountry"))->enabled) {
  507. if(strlen(opt->strarg) != 2 || !isalpha(opt->strarg[0]) || !isalpha(opt->strarg[1])) {
  508. logg("!SubmitDetectionStats: DetectionStatsCountry requires a two-letter country code\n");
  509. return 56;
  510. }
  511. country = opt->strarg;
  512. }
  513. if((opt = optget(opts, "DetectionStatsHostID"))->enabled) {
  514. if(strlen(opt->strarg) != 32) {
  515. logg("!SubmitDetectionStats: The unique ID must be 32 characters long\n");
  516. return 56;
  517. }
  518. hostid = opt->strarg;
  519. }
  520. if((opt = optget(opts, "HTTPUserAgent"))->enabled)
  521. strncpy(uastr, opt->strarg, sizeof(uastr));
  522. else
  523. snprintf(uastr, sizeof(uastr), PACKAGE"/%s (OS: "TARGET_OS_TYPE", ARCH: "TARGET_ARCH_TYPE", CPU: "TARGET_CPU_TYPE"):%s:%s", get_version(), country ? country : "", hostid ? hostid : "");
  524. uastr[sizeof(uastr) - 1] = 0;
  525. if((opt = optget(opts, "HTTPProxyServer"))->enabled) {
  526. proxy = opt->strarg;
  527. if(!strncasecmp(proxy, "http://", 7))
  528. proxy += 7;
  529. if((opt = optget(opts, "HTTPProxyUsername"))->enabled) {
  530. user = opt->strarg;
  531. if(!(opt = optget(opts, "HTTPProxyPassword"))->enabled) {
  532. logg("!SubmitDetectionStats: HTTPProxyUsername requires HTTPProxyPassword\n");
  533. return 56;
  534. }
  535. auth = proxyauth(user, opt->strarg);
  536. if(!auth)
  537. return 56;
  538. }
  539. if((opt = optget(opts, "HTTPProxyPort"))->enabled)
  540. port = opt->numarg;
  541. logg("*Connecting via %s\n", proxy);
  542. }
  543. if((clamsockd = clamd_connect(clamdcfg, "SubmitDetectionStats")) < 0)
  544. return 52;
  545. recvlninit(&rcv, clamsockd);
  546. if(sendln(clamsockd, "zDETSTATS", 10)) {
  547. closesocket(clamsockd);
  548. return 52;
  549. }
  550. ret = 0;
  551. memset(query, 0, sizeof(query));
  552. qcnt = 0;
  553. entries = 0;
  554. while(recvln(&rcv, &line, NULL) > 0) {
  555. if(cli_strtokenize(line, ':', 5, tokens) != 5) {
  556. logg("!SubmitDetectionStats: Invalid data format\n");
  557. ret = 52;
  558. break;
  559. }
  560. qcnt += snprintf(&query[qcnt], sizeof(query) - qcnt, "ts[]=%s&fname[]=%s&virus[]=%s(%s:%s)&", tokens[0], tokens[4], tokens[3], tokens[1], tokens[2]);
  561. entries++;
  562. if(entries == SUBMIT_MIN_ENTRIES) {
  563. sd = wwwconnect("stats.clamav.net", proxy, port, NULL, optget(opts, "LocalIPAddress")->strarg, optget(opts, "ConnectTimeout")->numarg, NULL, 0, 0);
  564. if(sd < 0) {
  565. logg("!SubmitDetectionStats: Can't connect to server\n");
  566. ret = 52;
  567. break;
  568. }
  569. query[sizeof(query) - 1] = 0;
  570. if(mdprintf(sd,
  571. "POST http://stats.clamav.net/submit.php HTTP/1.0\r\n"
  572. "Host: stats.clamav.net\r\n%s%s%s%s"
  573. "Content-Type: application/x-www-form-urlencoded\r\n"
  574. "User-Agent: %s\r\n"
  575. "Content-Length: %u\r\n\r\n"
  576. "%s",
  577. auth ? auth : "", hostid ? "X-HostID: " : "", hostid ? hostid : "", hostid ? "\r\n" : "", uastr, (unsigned int) strlen(query), query) < 0)
  578. {
  579. logg("!SubmitDetectionStats: Can't write to socket\n");
  580. ret = 52;
  581. closesocket(sd);
  582. break;
  583. }
  584. pt = post;
  585. cnt = sizeof(post) - 1;
  586. #ifdef SO_ERROR
  587. while((bread = wait_recv(sd, pt, cnt, 0, optget(opts, "ReceiveTimeout")->numarg)) > 0) {
  588. #else
  589. while((bread = recv(sd, pt, cnt, 0)) > 0) {
  590. #endif
  591. pt += bread;
  592. cnt -= bread;
  593. if(cnt <= 0)
  594. break;
  595. }
  596. *pt = 0;
  597. closesocket(sd);
  598. if(bread < 0) {
  599. logg("!SubmitDetectionStats: Can't read from socket\n");
  600. ret = 52;
  601. break;
  602. }
  603. if(strstr(post, "SUBMIT_OK")) {
  604. submitted += entries;
  605. if(submitted + SUBMIT_MIN_ENTRIES > SUBMIT_MAX_ENTRIES)
  606. break;
  607. qcnt = 0;
  608. entries = 0;
  609. memset(query, 0, sizeof(query));
  610. continue;
  611. }
  612. ret = 52;
  613. if((pt = strstr(post, "SUBMIT_PERMANENT_FAILURE"))) {
  614. if(!submitted) {
  615. permfail = 1;
  616. if((pt + 32 <= post + sizeof(post)) && pt[24] == ':')
  617. logg("!SubmitDetectionStats: Remote server reported permanent failure: %s\n", &pt[25]);
  618. else
  619. logg("!SubmitDetectionStats: Remote server reported permanent failure\n");
  620. }
  621. } else if((pt = strstr(post, "SUBMIT_TEMPORARY_FAILURE"))) {
  622. if(!submitted) {
  623. if((pt + 32 <= post + sizeof(post)) && pt[24] == ':')
  624. logg("!SubmitDetectionStats: Remote server reported temporary failure: %s\n", &pt[25]);
  625. else
  626. logg("!SubmitDetectionStats: Remote server reported temporary failure\n");
  627. }
  628. } else {
  629. if(!submitted)
  630. logg("!SubmitDetectionStats: Incorrect answer from server\n");
  631. }
  632. break;
  633. }
  634. }
  635. closesocket(clamsockd);
  636. if(auth)
  637. free(auth);
  638. if(ret == 0) {
  639. if(!submitted) {
  640. logg("SubmitDetectionStats: Not enough recent data for submission\n");
  641. } else {
  642. logg("SubmitDetectionStats: Submitted %u records\n", submitted);
  643. if((clamsockd = clamd_connect(clamdcfg, "SubmitDetectionStats")) != -1) {
  644. sendln(clamsockd, "DETSTATSCLEAR", 14);
  645. recv(clamsockd, query, sizeof(query), 0);
  646. closesocket(clamsockd);
  647. }
  648. }
  649. }
  650. return ret;
  651. }
  652. #else
  653. int submitstats(const char *clamdcfg, const struct optstruct *opts)
  654. {
  655. logg("clamd not built, no statistics");
  656. return 52;
  657. }
  658. #endif
  659. static int Rfc2822DateTime(char *buf, time_t mtime)
  660. {
  661. struct tm *gmt;
  662. gmt = gmtime(&mtime);
  663. if (!gmt) {
  664. logg("gmtime: %s\n", strerror(errno));
  665. strcpy(buf, "ERROR");
  666. return -1;
  667. }
  668. return strftime(buf, 36, "%a, %d %b %Y %X GMT", gmt);
  669. }
  670. static struct cl_cvd *remote_cvdhead(const char *cvdfile, const char *localfile, const char *hostname, char *ip, const char *localip, const char *proxy, int port, const char *user, const char *pass, const char *uas, int *ims, int ctimeout, int rtimeout, struct mirdat *mdat, int logerr, unsigned int can_whitelist)
  671. {
  672. char cmd[512], head[513], buffer[FILEBUFF], ipaddr[46], *ch, *tmp;
  673. int bread, cnt, sd;
  674. unsigned int i, j;
  675. char *remotename = NULL, *authorization = NULL;
  676. struct cl_cvd *cvd;
  677. char last_modified[36], uastr[128];
  678. if(proxy) {
  679. remotename = malloc(strlen(hostname) + 8);
  680. if(!remotename) {
  681. logg("!remote_cvdhead: Can't allocate memory for 'remotename'\n");
  682. return NULL;
  683. }
  684. sprintf(remotename, "http://%s", hostname);
  685. if(user) {
  686. authorization = proxyauth(user, pass);
  687. if(!authorization) {
  688. free(remotename);
  689. return NULL;
  690. }
  691. }
  692. }
  693. if(!access(localfile, R_OK)) {
  694. cvd = cl_cvdhead(localfile);
  695. if(!cvd) {
  696. logg("!remote_cvdhead: Can't parse file %s\n", localfile);
  697. free(remotename);
  698. free(authorization);
  699. return NULL;
  700. }
  701. Rfc2822DateTime(last_modified, (time_t) cvd->stime);
  702. cl_cvdfree(cvd);
  703. } else {
  704. time_t mtime = 1104119530;
  705. Rfc2822DateTime(last_modified, mtime);
  706. logg("*Assuming modification time in the past\n");
  707. }
  708. logg("*If-Modified-Since: %s\n", last_modified);
  709. logg("Reading CVD header (%s): ", cvdfile);
  710. if(uas)
  711. strncpy(uastr, uas, sizeof(uastr));
  712. else
  713. snprintf(uastr, sizeof(uastr), PACKAGE"/%s (OS: "TARGET_OS_TYPE", ARCH: "TARGET_ARCH_TYPE", CPU: "TARGET_CPU_TYPE")", get_version());
  714. uastr[sizeof(uastr) - 1] = 0;
  715. snprintf(cmd, sizeof(cmd),
  716. "GET %s/%s HTTP/1.0\r\n"
  717. "Host: %s\r\n%s"
  718. "User-Agent: %s\r\n"
  719. "Connection: close\r\n"
  720. "Range: bytes=0-511\r\n"
  721. "If-Modified-Since: %s\r\n"
  722. "\r\n", (remotename != NULL) ? remotename : "", cvdfile, hostname, (authorization != NULL) ? authorization : "", uastr, last_modified);
  723. free(remotename);
  724. free(authorization);
  725. memset(ipaddr, 0, sizeof(ipaddr));
  726. if(ip[0]) /* use ip to connect */
  727. sd = wwwconnect(ip, proxy, port, ipaddr, localip, ctimeout, mdat, logerr, can_whitelist);
  728. else
  729. sd = wwwconnect(hostname, proxy, port, ipaddr, localip, ctimeout, mdat, logerr, can_whitelist);
  730. if(sd < 0) {
  731. return NULL;
  732. } else {
  733. logg("*Connected to %s (IP: %s).\n", hostname, ipaddr);
  734. logg("*Trying to retrieve CVD header of http://%s/%s\n", hostname, cvdfile);
  735. }
  736. if(!ip[0])
  737. strcpy(ip, ipaddr);
  738. if(send(sd, cmd, strlen(cmd), 0) < 0) {
  739. logg("%cremote_cvdhead: write failed\n", logerr ? '!' : '^');
  740. closesocket(sd);
  741. return NULL;
  742. }
  743. tmp = buffer;
  744. cnt = FILEBUFF;
  745. #ifdef SO_ERROR
  746. while((bread = wait_recv(sd, tmp, cnt, 0, rtimeout)) > 0) {
  747. #else
  748. while((bread = recv(sd, tmp, cnt, 0)) > 0) {
  749. #endif
  750. tmp += bread;
  751. cnt -= bread;
  752. if(cnt <= 0)
  753. break;
  754. }
  755. closesocket(sd);
  756. if(bread == -1) {
  757. logg("%cremote_cvdhead: Error while reading CVD header from %s\n", logerr ? '!' : '^', hostname);
  758. mirman_update(mdat->currip, mdat->af, mdat, 1);
  759. return NULL;
  760. }
  761. if((strstr(buffer, "HTTP/1.1 404")) != NULL || (strstr(buffer, "HTTP/1.0 404")) != NULL) {
  762. logg("%cCVD file not found on remote server\n", logerr ? '!' : '^');
  763. mirman_update(mdat->currip, mdat->af, mdat, 2);
  764. return NULL;
  765. }
  766. /* check whether the resource is up-to-date */
  767. if((strstr(buffer, "HTTP/1.1 304")) != NULL || (strstr(buffer, "HTTP/1.0 304")) != NULL) {
  768. *ims = 0;
  769. logg("OK (IMS)\n");
  770. mirman_update(mdat->currip, mdat->af, mdat, 0);
  771. return NULL;
  772. } else {
  773. *ims = 1;
  774. }
  775. if(!strstr(buffer, "HTTP/1.1 200") && !strstr(buffer, "HTTP/1.0 200") &&
  776. !strstr(buffer, "HTTP/1.1 206") && !strstr(buffer, "HTTP/1.0 206")) {
  777. logg("%cUnknown response from remote server\n", logerr ? '!' : '^');
  778. mirman_update(mdat->currip, mdat->af, mdat, 1);
  779. return NULL;
  780. }
  781. i = 3;
  782. ch = buffer + i;
  783. while(i < sizeof(buffer)) {
  784. if (*ch == '\n' && *(ch - 1) == '\r' && *(ch - 2) == '\n' && *(ch - 3) == '\r') {
  785. ch++;
  786. i++;
  787. break;
  788. }
  789. ch++;
  790. i++;
  791. }
  792. if(sizeof(buffer) - i < 512) {
  793. logg("%cremote_cvdhead: Malformed CVD header (too short)\n", logerr ? '!' : '^');
  794. mirman_update(mdat->currip, mdat->af, mdat, 1);
  795. return NULL;
  796. }
  797. memset(head, 0, sizeof(head));
  798. for(j = 0; j < 512; j++) {
  799. if(!ch || (ch && !*ch) || (ch && !isprint(ch[j]))) {
  800. logg("%cremote_cvdhead: Malformed CVD header (bad chars)\n", logerr ? '!' : '^');
  801. mirman_update(mdat->currip, mdat->af, mdat, 1);
  802. return NULL;
  803. }
  804. head[j] = ch[j];
  805. }
  806. if(!(cvd = cl_cvdparse(head))) {
  807. logg("%cremote_cvdhead: Malformed CVD header (can't parse)\n", logerr ? '!' : '^');
  808. mirman_update(mdat->currip, mdat->af, mdat, 1);
  809. } else {
  810. logg("OK\n");
  811. mirman_update(mdat->currip, mdat->af, mdat, 0);
  812. }
  813. return cvd;
  814. }
  815. static int getfile_mirman(const char *srcfile, const char *destfile, const char *hostname, char *ip, const char *localip, const char *proxy, int port, const char *user, const char *pass, const char *uas, int ctimeout, int rtimeout, struct mirdat *mdat, int logerr, unsigned int can_whitelist, const char *ims, const char *ipaddr, int sd)
  816. {
  817. char cmd[512], uastr[128], buffer[FILEBUFF], *ch;
  818. int bread, fd, totalsize = 0, rot = 0, totaldownloaded = 0,
  819. percentage = 0;
  820. unsigned int i;
  821. char *remotename = NULL, *authorization = NULL, *headerline;
  822. const char *rotation = "|/-\\", *fname;
  823. if(proxy) {
  824. remotename = malloc(strlen(hostname) + 8);
  825. if(!remotename) {
  826. logg("!getfile: Can't allocate memory for 'remotename'\n");
  827. return 75; /* FIXME */
  828. }
  829. sprintf(remotename, "http://%s", hostname);
  830. if(user) {
  831. authorization = proxyauth(user, pass);
  832. if(!authorization) {
  833. free(remotename);
  834. return 75; /* FIXME */
  835. }
  836. }
  837. }
  838. if(ims)
  839. logg("*If-Modified-Since: %s\n", ims);
  840. if(uas)
  841. strncpy(uastr, uas, sizeof(uastr));
  842. else
  843. snprintf(uastr, sizeof(uastr), PACKAGE"/%s (OS: "TARGET_OS_TYPE", ARCH: "TARGET_ARCH_TYPE", CPU: "TARGET_CPU_TYPE")", get_version());
  844. uastr[sizeof(uastr) - 1] = 0;
  845. snprintf(cmd, sizeof(cmd),
  846. "GET %s/%s HTTP/1.0\r\n"
  847. "Host: %s\r\n%s"
  848. "User-Agent: %s\r\n"
  849. #ifdef FRESHCLAM_NO_CACHE
  850. "Cache-Control: no-cache\r\n"
  851. #endif
  852. "Connection: close\r\n"
  853. "%s%s%s"
  854. "\r\n", (remotename != NULL) ? remotename : "", srcfile, hostname, (authorization != NULL) ? authorization : "", uastr, ims ? "If-Modified-Since: " : "", ims ? ims : "", ims ? "\r\n": "");
  855. if(remotename)
  856. free(remotename);
  857. if(authorization)
  858. free(authorization);
  859. logg("*Trying to download http://%s/%s (IP: %s)\n", hostname, srcfile, ipaddr);
  860. if(ip && !ip[0])
  861. strcpy(ip, ipaddr);
  862. if(send(sd, cmd, strlen(cmd), 0) < 0) {
  863. logg("%cgetfile: Can't write to socket\n", logerr ? '!' : '^');
  864. return 52;
  865. }
  866. /* read http headers */
  867. ch = buffer;
  868. i = 0;
  869. while(1) {
  870. /* recv one byte at a time, until we reach \r\n\r\n */
  871. #ifdef SO_ERROR
  872. if((i >= sizeof(buffer) - 1) || wait_recv(sd, buffer + i, 1, 0, rtimeout) == -1) {
  873. #else
  874. if((i >= sizeof(buffer) - 1) || recv(sd, buffer + i, 1, 0) == -1) {
  875. #endif
  876. logg("%cgetfile: Error while reading database from %s (IP: %s): %s\n", logerr ? '!' : '^', hostname, ipaddr, strerror(errno));
  877. if(mdat)
  878. mirman_update(mdat->currip, mdat->af, mdat, 1);
  879. return 52;
  880. }
  881. if(i > 2 && *ch == '\n' && *(ch - 1) == '\r' && *(ch - 2) == '\n' && *(ch - 3) == '\r') {
  882. i++;
  883. break;
  884. }
  885. ch++;
  886. i++;
  887. }
  888. buffer[i] = 0;
  889. /* check whether the resource actually existed or not */
  890. if((strstr(buffer, "HTTP/1.1 404")) != NULL || (strstr(buffer, "HTTP/1.0 404")) != NULL) {
  891. logg("^getfile: %s not found on remote server (IP: %s)\n", srcfile, ipaddr);
  892. if(mdat)
  893. mirman_update(mdat->currip, mdat->af, mdat, 2);
  894. return 58;
  895. }
  896. /* If-Modified-Since */
  897. if(strstr(buffer, "HTTP/1.1 304") || strstr(buffer, "HTTP/1.0 304")) {
  898. if(mdat)
  899. mirman_update(mdat->currip, mdat->af, mdat, 0);
  900. return 1;
  901. }
  902. if(!strstr(buffer, "HTTP/1.1 200") && !strstr(buffer, "HTTP/1.0 200") &&
  903. !strstr(buffer, "HTTP/1.1 206") && !strstr(buffer, "HTTP/1.0 206")) {
  904. logg("%cgetfile: Unknown response from remote server (IP: %s)\n", logerr ? '!' : '^', ipaddr);
  905. if(mdat)
  906. mirman_update(mdat->currip, mdat->af, mdat, 1);
  907. return 58;
  908. }
  909. /* get size of resource */
  910. for(i = 0; (headerline = cli_strtok(buffer, i, "\n")); i++){
  911. if(strstr(headerline, "Content-Length:")) {
  912. if((ch = cli_strtok(headerline, 1, ": "))) {
  913. totalsize = atoi(ch);
  914. free(ch);
  915. } else {
  916. totalsize = 0;
  917. }
  918. }
  919. free(headerline);
  920. }
  921. if((fd = open(destfile, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, 0644)) == -1) {
  922. char currdir[512];
  923. if(getcwd(currdir, sizeof(currdir)))
  924. logg("!getfile: Can't create new file %s in %s\n", destfile, currdir);
  925. else
  926. logg("!getfile: Can't create new file %s in the current directory\n", destfile);
  927. logg("Hint: The database directory must be writable for UID %d or GID %d\n", getuid(), getgid());
  928. return 57;
  929. }
  930. if((fname = strrchr(srcfile, '/')))
  931. fname++;
  932. else
  933. fname = srcfile;
  934. #ifdef SO_ERROR
  935. while((bread = wait_recv(sd, buffer, FILEBUFF, 0, rtimeout)) > 0) {
  936. #else
  937. while((bread = recv(sd, buffer, FILEBUFF, 0)) > 0) {
  938. #endif
  939. if(write(fd, buffer, bread) != bread) {
  940. logg("getfile: Can't write %d bytes to %s\n", bread, destfile);
  941. close(fd);
  942. unlink(destfile);
  943. return 57; /* FIXME */
  944. }
  945. totaldownloaded += bread;
  946. if(totalsize > 0)
  947. percentage = (int) (100 * (float) totaldownloaded / totalsize);
  948. if(!mprintf_quiet) {
  949. if(totalsize > 0) {
  950. mprintf("Downloading %s [%3i%%]\r", fname, percentage);
  951. } else {
  952. mprintf("Downloading %s [%c]\r", fname, rotation[rot]);
  953. rot++;
  954. rot %= 4;
  955. }
  956. fflush(stdout);
  957. }
  958. }
  959. close(fd);
  960. if(bread == -1) {
  961. logg("%cgetfile: Download interrupted: %s (IP: %s)\n", logerr ? '!' : '^', strerror(errno), ipaddr);
  962. if(mdat)
  963. mirman_update(mdat->currip, mdat->af, mdat, 2);
  964. return 52;
  965. }
  966. if(!totaldownloaded)
  967. return 53;
  968. if(totalsize > 0)
  969. logg("Downloading %s [100%%]\n", fname);
  970. else
  971. logg("Downloading %s [*]\n", fname);
  972. if(mdat)
  973. mirman_update(mdat->currip, mdat->af, mdat, 0);
  974. return 0;
  975. }
  976. static int getfile(const char *srcfile, const char *destfile, const char *hostname, char *ip, const char *localip, const char *proxy, int port, const char *user, const char *pass, const char *uas, int ctimeout, int rtimeout, struct mirdat *mdat, int logerr, unsigned int can_whitelist, const char *ims, const struct optstruct *opts)
  977. {
  978. int ret, sd;
  979. char ipaddr[46];
  980. memset(ipaddr, 0, sizeof(ipaddr));
  981. if(ip && ip[0]) /* use ip to connect */
  982. sd = wwwconnect(ip, proxy, port, ipaddr, localip, ctimeout, mdat, logerr, can_whitelist);
  983. else
  984. sd = wwwconnect(hostname, proxy, port, ipaddr, localip, ctimeout, mdat, logerr, can_whitelist);
  985. if(sd < 0)
  986. return 52;
  987. if(mdat) {
  988. mirman_update_sf(mdat->currip, mdat->af, mdat, 0, 1);
  989. mirman_write("mirrors.dat", dbdir, mdat);
  990. }
  991. ret = getfile_mirman(srcfile, destfile, hostname, ip, localip, proxy, port, user, pass, uas, ctimeout, rtimeout, mdat, logerr, can_whitelist, ims, ipaddr, sd);
  992. closesocket(sd);
  993. if(mdat) {
  994. mirman_update_sf(mdat->currip, mdat->af, mdat, 0, -1);
  995. mirman_write("mirrors.dat", dbdir, mdat);
  996. }
  997. return ret;
  998. }
  999. static int getcvd(const char *cvdfile, const char *newfile, const char *hostname, char *ip, const char *localip, const char *proxy, int port, const char *user, const char *pass, const char *uas, unsigned int newver, int ctimeout, int rtimeout, struct mirdat *mdat, int logerr, unsigned int can_whitelist, const struct optstruct *opts)
  1000. {
  1001. struct cl_cvd *cvd;
  1002. int ret;
  1003. logg("*Retrieving http://%s/%s\n", hostname, cvdfile);
  1004. if((ret = getfile(cvdfile, newfile, hostname, ip, localip, proxy, port, user, pass, uas, ctimeout, rtimeout, mdat, logerr, can_whitelist, NULL, opts))) {
  1005. logg("%cCan't download %s from %s\n", logerr ? '!' : '^', cvdfile, hostname);
  1006. unlink(newfile);
  1007. return ret;
  1008. }
  1009. if((ret = cl_cvdverify(newfile))) {
  1010. logg("!Verification: %s\n", cl_strerror(ret));
  1011. unlink(newfile);
  1012. return 54;
  1013. }
  1014. if(!(cvd = cl_cvdhead(newfile))) {
  1015. logg("!Can't read CVD header of new %s database.\n", cvdfile);
  1016. unlink(newfile);
  1017. return 54;
  1018. }
  1019. if(cvd->version < newver) {
  1020. logg("^Mirror %s is not synchronized.\n", ip);
  1021. mirman_update(mdat->currip, mdat->af, mdat, 2);
  1022. cl_cvdfree(cvd);
  1023. unlink(newfile);
  1024. return 59;
  1025. }
  1026. cl_cvdfree(cvd);
  1027. return 0;
  1028. }
  1029. static int chdir_tmp(const char *dbname, const char *tmpdir)
  1030. {
  1031. char cvdfile[32];
  1032. if(access(tmpdir, R_OK|W_OK) == -1) {
  1033. sprintf(cvdfile, "%s.cvd", dbname);
  1034. if(access(cvdfile, R_OK) == -1) {
  1035. sprintf(cvdfile, "%s.cld", dbname);
  1036. if(access(cvdfile, R_OK) == -1) {
  1037. logg("!chdir_tmp: Can't access local %s database\n", dbname);
  1038. return -1;
  1039. }
  1040. }
  1041. if(mkdir(tmpdir, 0755) == -1) {
  1042. logg("!chdir_tmp: Can't create directory %s\n", tmpdir);
  1043. return -1;
  1044. }
  1045. if(cli_cvdunpack(cvdfile, tmpdir) == -1) {
  1046. logg("!chdir_tmp: Can't unpack %s into %s\n", cvdfile, tmpdir);
  1047. cli_rmdirs(tmpdir);
  1048. return -1;
  1049. }
  1050. }
  1051. if(chdir(tmpdir) == -1) {
  1052. logg("!chdir_tmp: Can't change directory to %s\n", tmpdir);
  1053. return -1;
  1054. }
  1055. return 0;
  1056. }
  1057. static int getpatch(const char *dbname, const char *tmpdir, int version, const char *hostname, char *ip, const char *localip, const char *proxy, int port, const char *user, const char *pass, const char *uas, int ctimeout, int rtimeout, struct mirdat *mdat, int logerr, unsigned int can_whitelist, const struct optstruct *opts)
  1058. {
  1059. char *tempname, patch[32], olddir[512];
  1060. int ret, fd;
  1061. if(!getcwd(olddir, sizeof(olddir))) {
  1062. logg("!getpatch: Can't get path of current working directory\n");
  1063. return 50; /* FIXME */
  1064. }
  1065. if(chdir_tmp(dbname, tmpdir) == -1)
  1066. return 50;
  1067. tempname = cli_gentemp(".");
  1068. snprintf(patch, sizeof(patch), "%s-%d.cdiff", dbname, version);
  1069. logg("*Retrieving http://%s/%s\n", hostname, patch);
  1070. if((ret = getfile(patch, tempname, hostname, ip, localip, proxy, port, user, pass, uas, ctimeout, rtimeout, mdat, logerr, can_whitelist, NULL, opts))) {
  1071. if(ret == 53)
  1072. logg("Empty script %s, need to download entire database\n", patch);
  1073. else
  1074. logg("%cgetpatch: Can't download %s from %s\n", logerr ? '!' : '^', patch, hostname);
  1075. unlink(tempname);
  1076. free(tempname);
  1077. CHDIR_ERR(olddir);
  1078. return ret;
  1079. }
  1080. if((fd = open(tempname, O_RDONLY|O_BINARY)) == -1) {
  1081. logg("!getpatch: Can't open %s for reading\n", tempname);
  1082. unlink(tempname);
  1083. free(tempname);
  1084. CHDIR_ERR(olddir);
  1085. return 55;
  1086. }
  1087. if(cdiff_apply(fd, 1) == -1) {
  1088. logg("!getpatch: Can't apply patch\n");
  1089. close(fd);
  1090. unlink(tempname);
  1091. free(tempname);
  1092. CHDIR_ERR(olddir);
  1093. return 70; /* FIXME */
  1094. }
  1095. close(fd);
  1096. unlink(tempname);
  1097. free(tempname);
  1098. if(chdir(olddir) == -1) {
  1099. logg("!getpatch: Can't chdir to %s\n", olddir);
  1100. return 50; /* FIXME */
  1101. }
  1102. return 0;
  1103. }
  1104. static struct cl_cvd *currentdb(const char *dbname, char *localname)
  1105. {
  1106. char db[32];
  1107. struct cl_cvd *cvd = NULL;
  1108. snprintf(db, sizeof(db), "%s.cvd", dbname);
  1109. if(localname)
  1110. strcpy(localname, db);
  1111. if(access(db, R_OK) == -1) {
  1112. snprintf(db, sizeof(db), "%s.cld", dbname);
  1113. if(localname)
  1114. strcpy(localname, db);
  1115. }
  1116. if(!access(db, R_OK))
  1117. cvd = cl_cvdhead(db);
  1118. return cvd;
  1119. }
  1120. static int buildcld(const char *tmpdir, const char *dbname, const char *newfile, unsigned int compr)
  1121. {
  1122. DIR *dir;
  1123. char cwd[512], info[32], buff[513], *pt;
  1124. struct dirent *dent;
  1125. int fd, err = 0;
  1126. gzFile gzs = NULL;
  1127. if(!getcwd(cwd, sizeof(cwd))) {
  1128. logg("!buildcld: Can't get path of current working directory\n");
  1129. return -1;
  1130. }
  1131. if(chdir(tmpdir) == -1) {
  1132. logg("!buildcld: Can't access directory %s\n", tmpdir);
  1133. return -1;
  1134. }
  1135. snprintf(info, sizeof(info), "%s.info", dbname);
  1136. if((fd = open(info, O_RDONLY|O_BINARY)) == -1) {
  1137. logg("!buildcld: Can't open %s\n", info);
  1138. CHDIR_ERR(cwd);
  1139. return -1;
  1140. }
  1141. if(read(fd, buff, 512) == -1) {
  1142. logg("!buildcld: Can't read %s\n", info);
  1143. CHDIR_ERR(cwd);
  1144. close(fd);
  1145. return -1;
  1146. }
  1147. buff[512] = 0;
  1148. close(fd);
  1149. if(!(pt = strchr(buff, '\n'))) {
  1150. logg("!buildcld: Bad format of %s\n", info);
  1151. CHDIR_ERR(cwd);
  1152. return -1;
  1153. }
  1154. memset(pt, ' ', 512 + buff - pt);
  1155. if((fd = open(newfile, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, 0644)) == -1) {
  1156. logg("!buildcld: Can't open %s for writing\n", newfile);
  1157. CHDIR_ERR(cwd);
  1158. return -1;
  1159. }
  1160. if(write(fd, buff, 512) != 512) {
  1161. logg("!buildcld: Can't write to %s\n", newfile);
  1162. CHDIR_ERR(cwd);
  1163. close(fd);
  1164. unlink(newfile);
  1165. return -1;
  1166. }
  1167. if((dir = opendir(".")) == NULL) {
  1168. logg("!buildcld: Can't open directory %s\n", tmpdir);
  1169. CHDIR_ERR(cwd);
  1170. close(fd);
  1171. unlink(newfile);
  1172. return -1;
  1173. }
  1174. if(compr) {
  1175. close(fd);
  1176. if(!(gzs = gzopen(newfile, "ab9f"))) {
  1177. logg("!buildcld: gzopen() failed for %s\n", newfile);
  1178. CHDIR_ERR(cwd);
  1179. closedir(dir);
  1180. unlink(newfile);
  1181. return -1;
  1182. }
  1183. }
  1184. if(access("COPYING", R_OK)) {
  1185. logg("!buildcld: COPYING file not found\n");
  1186. err = 1;
  1187. } else {
  1188. if(tar_addfile(fd, gzs, "COPYING") == -1) {
  1189. logg("!buildcld: Can't add COPYING to new %s.cld - please check if there is enough disk space available\n", dbname);
  1190. if(!strcmp(dbname, "main") || !strcmp(dbname, "safebrowsing"))
  1191. logg("Updates to main.cvd or safebrowsing.cvd may require 200MB of disk space or more\n");
  1192. err = 1;
  1193. }
  1194. }
  1195. if(!err && !access(info, R_OK)) {
  1196. if(tar_addfile(fd, gzs, info) == -1) {
  1197. logg("!buildcld: Can't add %s to new %s.cld - please check if there is enough disk space available\n", info, dbname);
  1198. if(!strcmp(dbname, "main") || !strcmp(dbname, "safebrowsing"))
  1199. logg("Updates to main.cvd or safebrowsing.cvd may require 200MB of disk space or more\n");
  1200. err = 1;
  1201. }
  1202. }
  1203. if(!err && !access("daily.cfg", R_OK)) {
  1204. if(tar_addfile(fd, gzs, "daily.cfg") == -1) {
  1205. logg("!buildcld: Can't add daily.cfg to new %s.cld - please check if there is enough disk space available\n", dbname);
  1206. err = 1;
  1207. }
  1208. }
  1209. if(err) {
  1210. CHDIR_ERR(cwd);
  1211. if(gzs)
  1212. gzclose(gzs);
  1213. else
  1214. close(fd);
  1215. closedir(dir);
  1216. unlink(newfile);
  1217. return -1;
  1218. }
  1219. while((dent = readdir(dir))) {
  1220. if(dent->d_ino)
  1221. {
  1222. if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..") || !strcmp(dent->d_name, "COPYING") || !strcmp(dent->d_name, "daily.cfg") || !strcmp(dent->d_name, info))
  1223. continue;
  1224. if(tar_addfile(fd, gzs, dent->d_name) == -1) {
  1225. logg("!buildcld: Can't add %s to new %s.cld - please check if there is enough disk space available\n", dent->d_name, dbname);
  1226. if(!strcmp(dbname, "main") || !strcmp(dbname, "safebrowsing"))
  1227. logg("Updates to main.cvd or safebrowsing.cvd may require 200MB of disk space or more\n");
  1228. CHDIR_ERR(cwd);
  1229. if(gzs)
  1230. gzclose(gzs);
  1231. else
  1232. close(fd);
  1233. closedir(dir);
  1234. unlink(newfile);
  1235. return -1;
  1236. }
  1237. }
  1238. }
  1239. closedir(dir);
  1240. if(gzs) {
  1241. if(gzclose(gzs)) {
  1242. logg("!buildcld: gzclose() failed for %s\n", newfile);
  1243. unlink(newfile);
  1244. return -1;
  1245. }
  1246. } else {
  1247. if(close(fd) == -1) {
  1248. logg("!buildcld: close() failed for %s\n", newfile);
  1249. unlink(newfile);
  1250. return -1;
  1251. }
  1252. }
  1253. if(chdir(cwd) == -1) {
  1254. logg("!buildcld: Can't return to previous directory %s\n", cwd);
  1255. return -1;
  1256. }
  1257. return 0;
  1258. }
  1259. static int test_database(const char *newfile, const char *newdb, int bytecode)
  1260. {
  1261. struct cl_engine *engine;
  1262. unsigned newsigs = 0;
  1263. int ret;
  1264. logg("*Loading signatures from %s\n", newdb);
  1265. if(!(engine = cl_engine_new())) {
  1266. return 55;
  1267. }
  1268. if((ret = cl_load(newfile, engine, &newsigs, CL_DB_PHISHING | CL_DB_PHISHING_URLS | CL_DB_BYTECODE | CL_DB_PUA)) != CL_SUCCESS) {
  1269. logg("!Failed to load new database: %s\n", cl_strerror(ret));
  1270. cl_engine_free(engine);
  1271. return 55;
  1272. }
  1273. if(bytecode && (ret = cli_bytecode_prepare2(engine, &engine->bcs, engine->dconf->bytecode/*FIXME: dconf has no sense here*/))) {
  1274. logg("!Failed to compile/load bytecode: %s\n", cl_strerror(ret));
  1275. cl_engine_free(engine);
  1276. return 55;
  1277. }
  1278. logg("*Properly loaded %u signatures from new %s\n", newsigs, newdb);
  1279. if(engine->domainlist_matcher && engine->domainlist_matcher->sha256_pfx_set.keys)
  1280. cli_hashset_destroy(&engine->domainlist_matcher->sha256_pfx_set);
  1281. cl_engine_free(engine);
  1282. return 0;
  1283. }
  1284. #ifndef WIN32
  1285. static int test_database_wrap(const char *file, const char *newdb, int bytecode)
  1286. {
  1287. char firstline[256];
  1288. char lastline[256];
  1289. int pipefd[2];
  1290. pid_t pid;
  1291. int status = 0, ret;
  1292. FILE *f;
  1293. if (pipe(pipefd) == -1) {
  1294. logg("^pipe() failed: %s\n", strerror(errno));
  1295. return test_database(file, newdb, bytecode);
  1296. }
  1297. switch ( pid = fork() ) {
  1298. case 0:
  1299. close(pipefd[0]);
  1300. dup2(pipefd[1], 2);
  1301. exit(test_database(file, newdb, bytecode));
  1302. case -1:
  1303. close(pipefd[0]);
  1304. close(pipefd[1]);
  1305. logg("^fork() failed: %s\n", strerror(errno));
  1306. return test_database(file, newdb, bytecode);
  1307. default:
  1308. /* read first / last line printed by child*/
  1309. close(pipefd[1]);
  1310. f = fdopen(pipefd[0], "r");
  1311. firstline[0] = 0;
  1312. lastline[0] = 0;
  1313. do {
  1314. if (!fgets(firstline, sizeof(firstline), f))
  1315. break;
  1316. /* ignore warning messages, otherwise the outdated warning will
  1317. * make us miss the important part of the error message */
  1318. } while (!strncmp(firstline, "LibClamAV Warning:", 18));
  1319. /* must read entire output, child doesn't like EPIPE */
  1320. while (fgets(lastline, sizeof(firstline), f)) {
  1321. /* print the full output only when LogVerbose or -v is given */
  1322. logg("*%s", lastline);
  1323. }
  1324. fclose(f);
  1325. while ((ret = waitpid(pid, &status, 0)) == -1 && errno == EINTR);
  1326. if (ret == -1 && errno != ECHILD)
  1327. logg("^waitpid() failed: %s\n", strerror(errno));
  1328. cli_chomp(firstline);
  1329. cli_chomp(lastline);
  1330. if (firstline[0]) {
  1331. logg("!During database load : %s%s%s\n",
  1332. firstline, lastline[0] ? " [...] " : "",
  1333. lastline);
  1334. }
  1335. if (WIFEXITED(status)) {
  1336. ret = WEXITSTATUS(status);
  1337. if (ret) {
  1338. logg("^Database load exited with status %d\n", ret);
  1339. return ret;
  1340. }
  1341. if (firstline[0])
  1342. logg("^Database successfully loaded, but there is stderr output\n");
  1343. return 0;
  1344. }
  1345. if (WIFSIGNALED(status)) {
  1346. logg("!Database load killed by signal %d\n", WTERMSIG(status));
  1347. return 55;
  1348. }
  1349. logg("^Unknown status from wait: %d\n", status);
  1350. return 55;
  1351. }
  1352. }
  1353. #else
  1354. static int test_database_wrap(const char *file, const char *newdb, int bytecode)
  1355. {
  1356. int ret = 55;
  1357. __try
  1358. {
  1359. ret = test_database(file, newdb, bytecode);
  1360. }
  1361. __except (logg("!Exception during database testing, code %08x\n",
  1362. GetExceptionCode()),
  1363. EXCEPTION_CONTINUE_SEARCH)
  1364. { }
  1365. return ret;
  1366. }
  1367. #endif
  1368. static int checkdbdir(void)
  1369. {
  1370. DIR *dir;
  1371. struct dirent *dent;
  1372. char fname[512], broken[513];
  1373. int ret, fret = 0;
  1374. if(!(dir = opendir(dbdir))) {
  1375. logg("!checkdbdir: Can't open directory %s\n", dbdir);
  1376. return -1;
  1377. }
  1378. while((dent = readdir(dir))) {
  1379. if(dent->d_ino) {
  1380. if(cli_strbcasestr(dent->d_name, ".cld") || cli_strbcasestr(dent->d_name, ".cvd")) {
  1381. snprintf(fname, sizeof(fname), "%s"PATHSEP"%s", dbdir, dent->d_name);
  1382. if((ret = cl_cvdverify(fname))) {
  1383. fret = -1;
  1384. mprintf("!Corrupted database file %s: %s\n", fname, cl_strerror(ret));
  1385. snprintf(broken, sizeof(broken), "%s.broken", fname);
  1386. if(!access(broken, R_OK))
  1387. unlink(broken);
  1388. if(rename(fname, broken)) {
  1389. if(unlink(fname))
  1390. mprintf("!Can't remove broken database file %s, please delete it manually and restart freshclam\n", fname);
  1391. } else {
  1392. mprintf("Corrupted database file renamed to %s\n", broken);
  1393. }
  1394. }
  1395. }
  1396. }
  1397. }
  1398. closedir(dir);
  1399. return fret;
  1400. }
  1401. extern int sigchld_wait;
  1402. static int updatedb(const char *dbname, const char *hostname, char *ip, int *signo, const struct optstruct *opts, const char *dnsreply, char *localip, int outdated, struct mirdat *mdat, int logerr, int extra)
  1403. {
  1404. struct cl_cvd *current, *remote;
  1405. const struct optstruct *opt;
  1406. unsigned int nodb = 0, currver = 0, newver = 0, port = 0, i, j;
  1407. int ret, ims = -1;
  1408. char *pt, cvdfile[32], localname[32], *tmpdir = NULL, *newfile, *newfile2, newdb[32];
  1409. char extradbinfo[64], *extradnsreply = NULL, squery[64];
  1410. const char *proxy = NULL, *user = NULL, *pass = NULL, *uas = NULL;
  1411. unsigned int flevel = cl_retflevel(), remote_flevel = 0, maxattempts;
  1412. unsigned int can_whitelist = 0, mirror_stats = 0;
  1413. #ifdef _WIN32
  1414. unsigned int w32 = 1;
  1415. #else
  1416. unsigned int w32 = 0;
  1417. #endif
  1418. int ctimeout, rtimeout;
  1419. if(cli_strbcasestr(hostname, ".clamav.net"))
  1420. mirror_stats = 1;
  1421. snprintf(cvdfile, sizeof(cvdfile), "%s.cvd", dbname);
  1422. if(!(current = currentdb(dbname, localname))) {
  1423. nodb = 1;
  1424. } else {
  1425. mdat->dbflevel = current->fl;
  1426. }
  1427. if(!nodb && !extra && dnsreply) {
  1428. int field = 0;
  1429. if(!strcmp(dbname, "main")) {
  1430. field = 1;
  1431. } else if(!strcmp(dbname, "daily")) {
  1432. field = 2;
  1433. } else if(!strcmp(dbname, "safebrowsing")) {
  1434. field = 6;
  1435. } else if(!strcmp(dbname, "bytecode")) {
  1436. field = 7;
  1437. } else {
  1438. logg("!updatedb: Unknown database name (%s) passed.\n", dbname);
  1439. cl_cvdfree(current);
  1440. return 70;
  1441. }
  1442. if(field && (pt = cli_strtok(dnsreply, field, ":"))) {
  1443. if(!cli_isnumber(pt)) {
  1444. logg("^Broken database version in TXT record.\n");
  1445. } else {
  1446. newver = atoi(pt);
  1447. logg("*%s version from DNS: %d\n", cvdfile, newver);
  1448. }
  1449. free(pt);
  1450. } else {
  1451. logg("^Invalid DNS reply. Falling back to HTTP mode.\n");
  1452. }
  1453. }
  1454. #ifdef HAVE_RESOLV_H
  1455. else if(!nodb && extra && !optget(opts, "no-dns")->enabled) {
  1456. snprintf(extradbinfo, sizeof(extradbinfo), "%s.cvd.clamav.net", dbname);
  1457. if((extradnsreply = dnsquery(extradbinfo, T_TXT, NULL))) {
  1458. if((pt = cli_strtok(extradnsreply, 1, ":"))) {
  1459. int rt;
  1460. time_t ct;
  1461. rt = atoi(pt);
  1462. free(pt);
  1463. time(&ct);
  1464. if((int) ct - rt > 10800) {
  1465. logg("^DNS record is older than 3 hours.\n");
  1466. free(extradnsreply);
  1467. extradnsreply = NULL;
  1468. }
  1469. } else {
  1470. logg("^No timestamp in TXT record for %s\n", cvdfile);
  1471. free(extradnsreply);
  1472. extradnsreply = NULL;
  1473. }
  1474. if((pt = cli_strtok(extradnsreply, 0, ":"))) {
  1475. if(!cli_isnumber(pt)) {
  1476. logg("^Broken database version in TXT record for %s\n", cvdfile);
  1477. } else {
  1478. newver = atoi(pt);
  1479. logg("*%s version from DNS: %d\n", cvdfile, newver);
  1480. }
  1481. free(pt);
  1482. } else {
  1483. logg("^Invalid DNS reply. Falling back to HTTP mode.\n");
  1484. }
  1485. }
  1486. }
  1487. #endif
  1488. if(dnsreply && !extra) {
  1489. if((pt = cli_strtok(dnsreply, 5, ":"))) {
  1490. remote_flevel = atoi(pt);
  1491. free(pt);
  1492. if(remote_flevel && (remote_flevel - flevel < 4))
  1493. can_whitelist = 1;
  1494. }
  1495. }
  1496. /* Initialize proxy settings */
  1497. if((opt = optget(opts, "HTTPProxyServer"))->enabled) {
  1498. proxy = opt->strarg;
  1499. if(strncasecmp(proxy, "http://", 7) == 0)
  1500. proxy += 7;
  1501. if((opt = optget(opts, "HTTPProxyUsername"))->enabled) {
  1502. user = opt->strarg;
  1503. if((opt = optget(opts, "HTTPProxyPassword"))->enabled) {
  1504. pass = opt->strarg;
  1505. } else {
  1506. logg("HTTPProxyUsername requires HTTPProxyPassword\n");
  1507. if(current)
  1508. cl_cvdfree(current);
  1509. return 56;
  1510. }
  1511. }
  1512. if((opt = optget(opts, "HTTPProxyPort"))->enabled)
  1513. port = opt->numarg;
  1514. logg("Connecting via %s\n", proxy);
  1515. }
  1516. if((opt = optget(opts, "HTTPUserAgent"))->enabled)
  1517. uas = opt->strarg;
  1518. ctimeout = optget(opts, "ConnectTimeout")->numarg;
  1519. rtimeout = optget(opts, "ReceiveTimeout")->numarg;
  1520. if(!nodb && !newver) {
  1521. remote = remote_cvdhead(cvdfile, localname, hostname, ip, localip, proxy, port, user, pass, uas, &ims, ctimeout, rtimeout, mdat, logerr, can_whitelist);
  1522. if(!nodb && !ims) {
  1523. logg("%s is up to date (version: %d, sigs: %d, f-level: %d, builder: %s)\n", localname, current->version, current->sigs, current->fl, current->builder);
  1524. *signo += current->sigs;
  1525. #ifdef HAVE_RESOLV_H
  1526. if(mirror_stats && strlen(ip)) {
  1527. snprintf(squery, sizeof(squery), "%s.%u.%u.%u.%u.%s.ping.clamav.net", dbname, current->version, flevel, 1, w32, ip);
  1528. dnsquery(squery, T_A, NULL);
  1529. }
  1530. #endif
  1531. cl_cvdfree(current);
  1532. return 1;
  1533. }
  1534. if(!remote) {
  1535. logg("^Can't read %s header from %s (IP: %s)\n", cvdfile, hostname, ip);
  1536. #ifdef HAVE_RESOLV_H
  1537. if(mirror_stats && strlen(ip)) {
  1538. snprintf(squery, sizeof(squery), "%s.%u.%u.%u.%u.%s.ping.clamav.net", dbname, current->version + 1, flevel, 0, w32, ip);
  1539. dnsquery(squery, T_A, NULL);
  1540. }
  1541. #endif
  1542. cl_cvdfree(current);
  1543. return 58;
  1544. }
  1545. newver = remote->version;
  1546. cl_cvdfree(remote);
  1547. }
  1548. if(!nodb && (current->version >= newver)) {
  1549. logg("%s is up to date (version: %d, sigs: %d, f-level: %d, builder: %s)\n", localname, current->version, current->sigs, current->fl, current->builder);
  1550. if(!outdated && flevel < current->fl) {
  1551. /* display warning even for already installed database */
  1552. logg("^Current functionality level = %d, recommended = %d\n", flevel, current->fl);
  1553. logg("Please check if ClamAV tools are linked against the proper version of libclamav\n");
  1554. logg("DON'T PANIC! Read http://www.clamav.net/support/faq\n");
  1555. }
  1556. *signo += current->sigs;
  1557. cl_cvdfree(current);
  1558. return 1;
  1559. }
  1560. if(current) {
  1561. currver = current->version;
  1562. cl_cvdfree(current);
  1563. }
  1564. /*
  1565. if(ipaddr[0]) {
  1566. hostfd = wwwconnect(ipaddr, proxy, port, NULL, localip);
  1567. } else {
  1568. hostfd = wwwconnect(hostname, proxy, port, ipaddr, localip);
  1569. if(!ip[0])
  1570. strcpy(ip, ipaddr);
  1571. }
  1572. if(hostfd < 0) {
  1573. if(ipaddr[0])
  1574. logg("Connection with %s (IP: %s) failed.\n", hostname, ipaddr);
  1575. else
  1576. logg("Connection with %s failed.\n", hostname);
  1577. return 52;
  1578. };
  1579. */
  1580. if(!optget(opts, "ScriptedUpdates")->enabled)
  1581. nodb = 1;
  1582. newfile = cli_gentemp(updtmpdir);
  1583. if(nodb) {
  1584. ret =

Large files files are truncated, but you can click here to view the full file