Browse code

freshclam: add initial support for DatabaseCustomURL

Tomasz Kojm authored on 2010/10/28 23:24:16
Showing 3 changed files
... ...
@@ -1,3 +1,7 @@
1
+Thu Oct 28 16:23:47 CEST 2010 (tk)
2
+----------------------------------
3
+ * freshclam: add initial support for DatabaseCustomURL
4
+
1 5
 Mon Oct 25 18:02:56 CEST 2010 (tk)
2 6
 ----------------------------------
3 7
  * V 0.96.4
... ...
@@ -1066,7 +1066,7 @@ static int getfile(const char *srcfile, const char *destfile, const char *hostna
1066 1066
 	free(authorization);
1067 1067
 
1068 1068
     memset(ipaddr, 0, sizeof(ipaddr));
1069
-    if(ip[0]) /* use ip to connect */
1069
+    if(ip && ip[0]) /* use ip to connect */
1070 1070
 	sd = wwwconnect(ip, proxy, port, ipaddr, localip, ctimeout, mdat, logerr, can_whitelist);
1071 1071
     else
1072 1072
 	sd = wwwconnect(hostname, proxy, port, ipaddr, localip, ctimeout, mdat, logerr, can_whitelist);
... ...
@@ -1077,7 +1077,7 @@ static int getfile(const char *srcfile, const char *destfile, const char *hostna
1077 1077
 	logg("*Trying to download http://%s/%s (IP: %s)\n", hostname, srcfile, ipaddr);
1078 1078
     }
1079 1079
 
1080
-    if(!ip[0])
1080
+    if(ip && !ip[0])
1081 1081
 	strcpy(ip, ipaddr);
1082 1082
 
1083 1083
     if(send(sd, cmd, strlen(cmd), 0) < 0) {
... ...
@@ -1097,7 +1097,8 @@ static int getfile(const char *srcfile, const char *destfile, const char *hostna
1097 1097
 	if((i >= sizeof(buffer) - 1) || recv(sd, buffer + i, 1, 0) == -1) {
1098 1098
 #endif
1099 1099
 	    logg("%cgetfile: Error while reading database from %s (IP: %s): %s\n", logerr ? '!' : '^', hostname, ipaddr, strerror(errno));
1100
-	    mirman_update(mdat->currip, mdat->af, mdat, 1);
1100
+	    if(mdat)
1101
+		mirman_update(mdat->currip, mdat->af, mdat, 1);
1101 1102
 	    closesocket(sd);
1102 1103
 	    return 52;
1103 1104
 	}
... ...
@@ -1115,7 +1116,8 @@ static int getfile(const char *srcfile, const char *destfile, const char *hostna
1115 1115
     /* check whether the resource actually existed or not */
1116 1116
     if((strstr(buffer, "HTTP/1.1 404")) != NULL || (strstr(buffer, "HTTP/1.0 404")) != NULL) { 
1117 1117
 	logg("^getfile: %s not found on remote server (IP: %s)\n", srcfile, ipaddr);
1118
-	mirman_update(mdat->currip, mdat->af, mdat, 2);
1118
+	if(mdat)
1119
+	    mirman_update(mdat->currip, mdat->af, mdat, 2);
1119 1120
 	closesocket(sd);
1120 1121
 	return 58;
1121 1122
     }
... ...
@@ -1123,7 +1125,8 @@ static int getfile(const char *srcfile, const char *destfile, const char *hostna
1123 1123
     if(!strstr(buffer, "HTTP/1.1 200") && !strstr(buffer, "HTTP/1.0 200") &&
1124 1124
        !strstr(buffer, "HTTP/1.1 206") && !strstr(buffer, "HTTP/1.0 206")) {
1125 1125
 	logg("%cgetfile: Unknown response from remote server (IP: %s)\n", logerr ? '!' : '^', ipaddr);
1126
-	mirman_update(mdat->currip, mdat->af, mdat, 1);
1126
+	if(mdat)
1127
+	    mirman_update(mdat->currip, mdat->af, mdat, 1);
1127 1128
 	closesocket(sd);
1128 1129
 	return 58;
1129 1130
     }
... ...
@@ -1187,7 +1190,8 @@ static int getfile(const char *srcfile, const char *destfile, const char *hostna
1187 1187
 
1188 1188
     if(bread == -1) {
1189 1189
 	logg("%cgetfile: Download interrupted: %s (IP: %s)\n", logerr ? '!' : '^', strerror(errno), ipaddr);
1190
-	mirman_update(mdat->currip, mdat->af, mdat, 2);
1190
+	if(mdat)
1191
+	    mirman_update(mdat->currip, mdat->af, mdat, 2);
1191 1192
 	return 52;
1192 1193
     }
1193 1194
 
... ...
@@ -1199,7 +1203,8 @@ static int getfile(const char *srcfile, const char *destfile, const char *hostna
1199 1199
     else
1200 1200
         logg("Downloading %s [*]\n", srcfile);
1201 1201
 
1202
-    mirman_update(mdat->currip, mdat->af, mdat, 0);
1202
+    if(mdat)
1203
+	mirman_update(mdat->currip, mdat->af, mdat, 0);
1203 1204
     return 0;
1204 1205
 }
1205 1206
 
... ...
@@ -1842,6 +1847,170 @@ static int updatedb(const char *dbname, const char *hostname, char *ip, int *sig
1842 1842
     return 0;
1843 1843
 }
1844 1844
 
1845
+static int updatecustomdb(const char *url, int *signo, const struct optstruct *opts, char *localip, int logerr)
1846
+{
1847
+	const struct optstruct *opt;
1848
+	unsigned int port = 0, newsigs = 0;
1849
+	int ret;
1850
+	char *pt, *host, urlcpy[256], *newfile = NULL, *newfile2, newdb[32];
1851
+	const char *proxy = NULL, *user = NULL, *pass = NULL, *uas = NULL, *rpath, *dbname;
1852
+	int ctimeout, rtimeout;
1853
+	struct cl_engine *engine;
1854
+
1855
+
1856
+    if(!strncasecmp(url, "http://", 7)) {
1857
+	strncpy(urlcpy, url, sizeof(urlcpy));
1858
+	host = &urlcpy[7];
1859
+	if(!(pt = strchr(host, '/'))) {
1860
+	    logg("!DatabaseCustomURL: Incorrect URL\n");
1861
+	    return 70;
1862
+	}
1863
+	*pt = 0;
1864
+	rpath = &url[pt - urlcpy];
1865
+	dbname = strrchr(url, '/') + 1;
1866
+	if(!dbname || strlen(dbname) < 4) {
1867
+	    logg("DatabaseCustomURL: Incorrect URL\n");
1868
+	    return 70;
1869
+	}
1870
+
1871
+	/* Initialize proxy settings */
1872
+	if((opt = optget(opts, "HTTPProxyServer"))->enabled) {
1873
+	    proxy = opt->strarg;
1874
+	    if(strncasecmp(proxy, "http://", 7) == 0)
1875
+		proxy += 7;
1876
+
1877
+	    if((opt = optget(opts, "HTTPProxyUsername"))->enabled) {
1878
+		user = opt->strarg;
1879
+		if((opt = optget(opts, "HTTPProxyPassword"))->enabled) {
1880
+		    pass = opt->strarg;
1881
+		} else {
1882
+		    logg("HTTPProxyUsername requires HTTPProxyPassword\n");
1883
+		    return 56;
1884
+		}
1885
+	    }
1886
+	    if((opt = optget(opts, "HTTPProxyPort"))->enabled)
1887
+		port = opt->numarg;
1888
+	    logg("Connecting via %s\n", proxy);
1889
+	}
1890
+
1891
+	if((opt = optget(opts, "HTTPUserAgent"))->enabled)
1892
+	    uas = opt->strarg;
1893
+
1894
+	ctimeout = optget(opts, "ConnectTimeout")->numarg;
1895
+	rtimeout = optget(opts, "ReceiveTimeout")->numarg;
1896
+
1897
+	newfile = cli_gentemp(updtmpdir);
1898
+	if((ret = getfile(rpath, newfile, host, NULL, localip, proxy, port, user, pass, uas, ctimeout, rtimeout, NULL, logerr, 0))) {
1899
+	    logg("%cCan't download %s from %s\n", logerr ? '!' : '^', dbname, host);
1900
+	    unlink(newfile);
1901
+	    free(newfile);
1902
+	    return ret;
1903
+	}
1904
+
1905
+	/* FIXME: add IMS support
1906
+	if(!nodb && (current->version >= newver)) {
1907
+	    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);
1908
+
1909
+	    *signo += current->sigs;
1910
+	    cl_cvdfree(current);
1911
+	    return 1;
1912
+	}
1913
+	*/
1914
+
1915
+    } else if(!strncasecmp(url, "file://", 7)) {
1916
+	rpath = &url[7];
1917
+#ifdef _WIN32
1918
+	dbname = strrchr(rpath, '\\');
1919
+#else
1920
+	dbname = strrchr(rpath, '/');
1921
+#endif
1922
+	if(!dbname || strlen(dbname++) < 5) {
1923
+	    logg("DatabaseCustomURL: Incorrect URL\n");
1924
+	    return 70;
1925
+	}
1926
+
1927
+	newfile = cli_gentemp(updtmpdir);
1928
+	if(!newfile)
1929
+	    return 70;
1930
+
1931
+	/* FIXME: preserve file permissions, calculate % */
1932
+	logg("Downloading %s [  0%%]\r", dbname);
1933
+	if(cli_filecopy(rpath, newfile) == -1) {
1934
+	    logg("DatabaseCustomURL: Can't copy file %s into database directory\n", rpath);
1935
+	    free(newfile);
1936
+	    return 70;
1937
+	}
1938
+	logg("Downloading %s [100%%]\n", dbname);
1939
+    } else {
1940
+	logg("!DatabaseCustomURL: Not supported protocol\n");
1941
+	return 70;
1942
+    }
1943
+
1944
+    if(optget(opts, "TestDatabases")->enabled && strlen(newfile) > 4) {
1945
+	newfile2 = malloc(strlen(newfile) + strlen(dbname) + 1);
1946
+	if(!newfile2) {
1947
+	    unlink(newfile);
1948
+	    free(newfile);
1949
+	    return 55;
1950
+	}
1951
+	sprintf(newfile2, "%s%s", newfile, dbname);
1952
+	newfile2[strlen(newfile) + strlen(dbname)] = 0;
1953
+	if(rename(newfile, newfile2) == -1) {
1954
+	    logg("!Can't rename %s to %s: %s\n", newfile, newfile2, strerror(errno));
1955
+	    unlink(newfile);
1956
+	    free(newfile);
1957
+	    free(newfile2);
1958
+	    return 57;
1959
+	}
1960
+	free(newfile);
1961
+	newfile = newfile2;
1962
+	if(!(engine = cl_engine_new())) {
1963
+	    unlink(newfile);
1964
+	    free(newfile);
1965
+	    return 55;
1966
+	}
1967
+	if((ret = cl_load(newfile, engine, &newsigs, CL_DB_PHISHING | CL_DB_PHISHING_URLS | CL_DB_BYTECODE | CL_DB_PUA)) != CL_SUCCESS) {
1968
+	    logg("!Failed to load new database: %s\n", cl_strerror(ret));
1969
+	    unlink(newfile);
1970
+	    free(newfile);
1971
+	    cl_engine_free(engine);
1972
+	    return 55;
1973
+	}
1974
+	if(optget(opts, "Bytecode")->enabled && (ret = cli_bytecode_prepare2(engine, &engine->bcs, engine->dconf->bytecode/*FIXME: dconf has no sense here*/))) {
1975
+	    logg("!Failed to compile/load bytecode: %s\n", cl_strerror(ret));
1976
+	    unlink(newfile);
1977
+	    free(newfile);
1978
+	    cl_engine_free(engine);
1979
+	    return 55;
1980
+	}
1981
+	logg("*Properly loaded %u signatures from new %s\n", newsigs, newdb);
1982
+	if(engine->domainlist_matcher && engine->domainlist_matcher->sha256_pfx_set.keys)
1983
+	    cli_hashset_destroy(&engine->domainlist_matcher->sha256_pfx_set);
1984
+	cl_engine_free(engine);
1985
+    }
1986
+
1987
+#ifdef _WIN32
1988
+    if(!access(dbname, R_OK) && unlink(dbname)) {
1989
+	logg("!Can't unlink %s. Please fix the problem manually and try again.\n", newdb);
1990
+	unlink(newfile);
1991
+	free(newfile);
1992
+	return 53;
1993
+    }
1994
+#endif
1995
+
1996
+    if(rename(newfile, dbname) == -1) {
1997
+	logg("!Can't rename %s to %s: %s\n", newfile, dbname, strerror(errno));
1998
+	unlink(newfile);
1999
+	free(newfile);
2000
+	return 57;
2001
+    }
2002
+    free(newfile);
2003
+    logg("%s updated (custom database)\n", dbname);
2004
+
2005
+    /* FIXME *signo += current->sigs; */
2006
+    return 0;
2007
+}
2008
+
1845 2009
 int downloadmanager(const struct optstruct *opts, const char *hostname, const char *dbdir, int logerr)
1846 2010
 {
1847 2011
 	time_t currtime;
... ...
@@ -2046,11 +2215,20 @@ int downloadmanager(const struct optstruct *opts, const char *hostname, const ch
2046 2046
 	}
2047 2047
     }
2048 2048
 
2049
+    /* custom dbs */
2050
+    if((opt = optget(opts, "DatabaseCustomURL"))->enabled) {
2051
+	while(opt) {
2052
+	    if(updatecustomdb(opt->strarg, &signo, opts, localip, logerr) == 0)
2053
+		updated = 1;
2054
+	    opt = opt->nextarg;
2055
+	}
2056
+    }
2057
+
2049 2058
     mirman_write("mirrors.dat", &mdat);
2050 2059
     cli_rmdirs(updtmpdir);
2051 2060
 
2052 2061
     if(updated) {
2053
-	if(optget(opts, "HTTPProxyServer")->enabled) {
2062
+	if(optget(opts, "HTTPProxyServer")->enabled || !ipaddr[0]) {
2054 2063
 	    logg("Database updated (%d signatures) from %s\n", signo, hostname);
2055 2064
 	} else {
2056 2065
 	    logg("Database updated (%d signatures) from %s (IP: %s)\n", signo, hostname, ipaddr);
... ...
@@ -360,6 +360,8 @@ const struct clam_option __clam_options[] = {
360 360
 
361 361
     { "ExtraDatabase", NULL, 0, TYPE_STRING, NULL, -1, NULL, FLAG_MULTIPLE, OPT_FRESHCLAM, "Download additional database. This option can be used multiple times.", "dbname1\ndbname2" },
362 362
 
363
+    { "DatabaseCustomURL", NULL, 0, TYPE_STRING, NULL, -1, NULL, FLAG_MULTIPLE, OPT_FRESHCLAM, "With this option you can provide custom sources (http:// or file://) for database files.\nThis option can be used multiple times.", "http://myserver.com/mysigs.ndb\nfile:///mnt/nfs/local.hdb" },
364
+
363 365
     { "HTTPProxyServer", NULL, 0, TYPE_STRING, NULL, -1, NULL, 0, OPT_FRESHCLAM, "If you're behind a proxy, please enter its address here.", "your-proxy" },
364 366
 
365 367
     { "HTTPProxyPort", NULL, 0, TYPE_NUMBER, MATCH_NUMBER, -1, NULL, 0, OPT_FRESHCLAM, "HTTP proxy's port", "8080" },