Browse code

scan meta-data in RAR files

git-svn-id: file:///var/lib/svn/clamav-devel/trunk/clamav-devel@1400 77e5149b-7576-45b1-b177-96237e5ba77b

Tomasz Kojm authored on 2005/03/18 10:27:45
Showing 6 changed files
... ...
@@ -1,3 +1,7 @@
1
+Fri Mar 18 02:24:05 CET 2005 (tk)
2
+---------------------------------
3
+  * libclamav: scan meta-data in RAR files
4
+
1 5
 Wed Mar 16 21:55:44 CET 2005 (tk)
2 6
 ---------------------------------
3 7
   * libclamav/pe.c: fix section handling in petite block
... ...
@@ -121,10 +121,10 @@ struct cli_md5_node {
121 121
     struct cli_md5_node *next;
122 122
 };
123 123
 
124
-struct cli_zip_node {
125
-    int compr, csize, size, encrypted, crc32, fileno, maxdepth;
124
+struct cli_meta_node {
125
+    int method, csize, size, encrypted, crc32, fileno, maxdepth;
126 126
     char *filename, *virname;
127
-    struct cli_zip_node *next;
127
+    struct cli_meta_node *next;
128 128
 };
129 129
 
130 130
 struct cl_node {
... ...
@@ -143,7 +143,11 @@ struct cl_node {
143 143
     struct cli_md5_node **md5_hlist;
144 144
 
145 145
     /* Zip metadata */
146
-    struct cli_zip_node *zip_mlist;
146
+    struct cli_meta_node *zip_mlist;
147
+
148
+    /* RAR metadata */
149
+    struct cli_meta_node *rar_mlist;
150
+
147 151
 };
148 152
 
149 153
 struct cl_limits {
... ...
@@ -390,7 +390,7 @@ void cl_free(struct cl_node *root)
390 390
 {
391 391
 	int i;
392 392
 	struct cli_md5_node *md5pt, *md5h;
393
-	struct cli_zip_node *zippt, *ziph;
393
+	struct cli_meta_node *metapt, *metah;
394 394
 
395 395
     if(!root) {
396 396
 	cli_errmsg("cl_free: root == NULL\n");
... ...
@@ -432,14 +432,24 @@ void cl_free(struct cl_node *root)
432 432
 	free(root->md5_hlist);
433 433
     }
434 434
 
435
-    zippt = root->zip_mlist;
436
-    while(zippt) {
437
-	ziph = zippt;
438
-	zippt = zippt->next;
439
-	free(ziph->virname);
440
-	if(ziph->filename)
441
-	    free(ziph->filename);
442
-	free(ziph);
435
+    metapt = root->zip_mlist;
436
+    while(metapt) {
437
+	metah = metapt;
438
+	metapt = metapt->next;
439
+	free(metah->virname);
440
+	if(metah->filename)
441
+	    free(metah->filename);
442
+	free(metah);
443
+    }
444
+
445
+    metapt = root->rar_mlist;
446
+    while(metapt) {
447
+	metah = metapt;
448
+	metapt = metapt->next;
449
+	free(metah->virname);
450
+	if(metah->filename)
451
+	    free(metah->filename);
452
+	free(metah);
443 453
     }
444 454
 
445 455
     free(root);
... ...
@@ -705,11 +705,11 @@ static int cli_loadhdb(FILE *fd, struct cl_node **root, unsigned int *signo, uns
705 705
     return 0;
706 706
 }
707 707
 
708
-static int cli_loadzmd(FILE *fd, struct cl_node **root, unsigned int *signo)
708
+static int cli_loadmd(FILE *fd, struct cl_node **root, unsigned int *signo, int type)
709 709
 {
710 710
 	char buffer[FILEBUFF], *pt;
711 711
 	int line = 0, comments = 0, ret = 0;
712
-	struct cli_zip_node *new;
712
+	struct cli_meta_node *new;
713 713
 
714 714
 
715 715
     if(!*root) {
... ...
@@ -728,7 +728,7 @@ static int cli_loadzmd(FILE *fd, struct cl_node **root, unsigned int *signo)
728 728
 
729 729
 	cli_chomp(buffer);
730 730
 
731
-	new = (struct cli_zip_node *) cli_calloc(1, sizeof(struct cli_zip_node));
731
+	new = (struct cli_meta_node *) cli_calloc(1, sizeof(struct cli_meta_node));
732 732
 	if(!new) {
733 733
 	    ret = CL_EMEM;
734 734
 	    break;
... ...
@@ -817,9 +817,9 @@ static int cli_loadzmd(FILE *fd, struct cl_node **root, unsigned int *signo)
817 817
 	    break;
818 818
 	} else {
819 819
 	    if(!strcmp(pt, "*"))
820
-		new->compr = -1;
820
+		new->method = -1;
821 821
 	    else
822
-		new->compr = atoi(pt);
822
+		new->method = atoi(pt);
823 823
 	    free(pt);
824 824
 	}
825 825
 
... ...
@@ -851,8 +851,13 @@ static int cli_loadzmd(FILE *fd, struct cl_node **root, unsigned int *signo)
851 851
 	    free(pt);
852 852
 	}
853 853
 
854
-	new->next = (*root)->zip_mlist;
855
-	(*root)->zip_mlist = new;
854
+	if(type == 1) {
855
+	    new->next = (*root)->zip_mlist;
856
+	    (*root)->zip_mlist = new;
857
+	} else {
858
+	    new->next = (*root)->rar_mlist;
859
+	    (*root)->rar_mlist = new;
860
+	}
856 861
     }
857 862
 
858 863
     if(!line) {
... ...
@@ -907,7 +912,10 @@ int cl_loaddb(const char *filename, struct cl_node **root, unsigned int *signo)
907 907
 	ret = cli_loadndb(fd, root, signo);
908 908
 
909 909
     } else if(cli_strbcasestr(filename, ".zmd")) {
910
-	ret = cli_loadzmd(fd, root, signo);
910
+	ret = cli_loadmd(fd, root, signo, 1);
911
+
912
+    } else if(cli_strbcasestr(filename, ".rmd")) {
913
+	ret = cli_loadmd(fd, root, signo, 2);
911 914
 
912 915
     } else {
913 916
 	cli_dbgmsg("cl_loaddb: unknown extension - assuming old database format\n");
... ...
@@ -958,9 +966,10 @@ int cl_loaddbdir(const char *dirname, struct cl_node **root, unsigned int *signo
958 958
 	     cli_strbcasestr(dent->d_name, ".db2")  ||
959 959
 	     cli_strbcasestr(dent->d_name, ".db3")  ||
960 960
 	     cli_strbcasestr(dent->d_name, ".hdb")  ||
961
-	     cli_strbcasestr(dent->d_name, ".fp")  ||
961
+	     cli_strbcasestr(dent->d_name, ".fp")   ||
962 962
 	     cli_strbcasestr(dent->d_name, ".ndb")  ||
963 963
 	     cli_strbcasestr(dent->d_name, ".zmd")  ||
964
+	     cli_strbcasestr(dent->d_name, ".rmd")  ||
964 965
 	     cli_strbcasestr(dent->d_name, ".cvd"))) {
965 966
 
966 967
 		dbfile = (char *) cli_calloc(strlen(dent->d_name) + strlen(dirname) + 2, sizeof(char));
... ...
@@ -1040,6 +1049,7 @@ int cl_statinidir(const char *dirname, struct cl_stat *dbstat)
1040 1040
 	    cli_strbcasestr(dent->d_name, ".fp")  || 
1041 1041
 	    cli_strbcasestr(dent->d_name, ".ndb")  || 
1042 1042
 	    cli_strbcasestr(dent->d_name, ".zmd")  || 
1043
+	    cli_strbcasestr(dent->d_name, ".rmd")  || 
1043 1044
 	    cli_strbcasestr(dent->d_name, ".cvd"))) {
1044 1045
 
1045 1046
 		dbstat->no++;
... ...
@@ -1110,6 +1120,7 @@ int cl_statchkdir(const struct cl_stat *dbstat)
1110 1110
 	    cli_strbcasestr(dent->d_name, ".fp")  || 
1111 1111
 	    cli_strbcasestr(dent->d_name, ".ndb")  || 
1112 1112
 	    cli_strbcasestr(dent->d_name, ".zmd")  || 
1113
+	    cli_strbcasestr(dent->d_name, ".rmd")  || 
1113 1114
 	    cli_strbcasestr(dent->d_name, ".cvd"))) {
1114 1115
 
1115 1116
                 fname = cli_calloc(strlen(dbstat->dir) + strlen(dent->d_name) + 2, sizeof(char));
... ...
@@ -120,23 +120,23 @@ static void cli_unlock_mutex(void *mtx)
120 120
 static int cli_scanrar(int desc, const char **virname, long int *scanned, const struct cl_node *root, const struct cl_limits *limits, unsigned int options, int *arec, int *mrec)
121 121
 {
122 122
 	FILE *tmp = NULL;
123
-	int files = 0, fd, ret = CL_CLEAN, afiles;
123
+	int files = 0, fd, ret = CL_CLEAN, afiles, encrypted;
124 124
 	ArchiveList_struct *rarlist = NULL;
125 125
 	ArchiveList_struct *rarlist_head = NULL;
126 126
 	char *rar_data_ptr;
127 127
 	unsigned long rar_data_size;
128
+	struct cli_meta_node *mdata;
128 129
 
129 130
 
130 131
     cli_dbgmsg("in scanrar()\n");
131 132
 
132
-
133 133
 #ifdef CL_THREAD_SAFE
134 134
     pthread_cleanup_push(cli_unlock_mutex, &cli_scanrar_mutex);
135 135
     pthread_mutex_lock(&cli_scanrar_mutex);
136 136
     cli_scanrar_inuse = 1;
137 137
 #endif
138 138
 
139
-    if(! (afiles = urarlib_list(desc, (ArchiveList_struct *) &rarlist))) {
139
+    if(!(afiles = urarlib_list(desc, (ArchiveList_struct *) &rarlist))) {
140 140
 #ifdef CL_THREAD_SAFE
141 141
 	pthread_mutex_unlock(&cli_scanrar_mutex);
142 142
 	cli_scanrar_inuse = 0;
... ...
@@ -149,8 +149,52 @@ static int cli_scanrar(int desc, const char **virname, long int *scanned, const
149 149
     rarlist_head = rarlist;
150 150
 
151 151
     while(rarlist) {
152
+
153
+	files++;
154
+	encrypted = rarlist->item.Flags & 0x04;
155
+
156
+	cli_dbgmsg("RAR: %s, crc32: 0x%x, encrypted: %d, compressed: %u, normal: %u, method: %d, ratio: %d (max: %d)\n", rarlist->item.Name, rarlist->item.FileCRC, encrypted, rarlist->item.PackSize, rarlist->item.UnpSize, rarlist->item.Method, rarlist->item.PackSize ? (rarlist->item.UnpSize / rarlist->item.PackSize) : 0, limits ? limits->maxratio : -1);
157
+
158
+	/* Scan metadata */
159
+	mdata = root->rar_mlist;
160
+	if(mdata) do {
161
+	    if(mdata->encrypted != encrypted)
162
+		continue;
163
+
164
+	    if(mdata->crc32 && mdata->crc32 != rarlist->item.FileCRC)
165
+		continue;
166
+
167
+	    if(mdata->csize > 0 && mdata->csize != rarlist->item.PackSize)
168
+		continue;
169
+
170
+	    if(mdata->size >= 0 && mdata->size != rarlist->item.UnpSize)
171
+		continue;
172
+
173
+	    if(mdata->method >= 0 && mdata->method != rarlist->item.Method)
174
+		continue;
175
+
176
+	    if(mdata->fileno && mdata->fileno != files)
177
+		continue;
178
+
179
+	    if(mdata->maxdepth && *arec > mdata->maxdepth)
180
+		continue;
181
+
182
+	    /* TODO add support for regex */
183
+	    /*if(mdata->filename && !strstr(zdirent.d_name, mdata->filename))*/
184
+	    if(mdata->filename && strcmp(rarlist->item.Name, mdata->filename))
185
+		continue;
186
+
187
+	    break; /* matched */
188
+
189
+	} while((mdata = mdata->next));
190
+
191
+	if(mdata) {
192
+	    *virname = mdata->virname;
193
+	    ret = CL_VIRUS;
194
+	    break;
195
+	}
196
+
152 197
 	if(DETECT_ENCRYPTED && (rarlist->item.Flags & 0x04)) {
153
-	    files++;
154 198
 	    cli_dbgmsg("RAR: Encrypted files found in archive.\n");
155 199
 	    lseek(desc, 0, SEEK_SET);
156 200
 	    ret = cli_scandesc(desc, virname, scanned, root, 0, 0);
... ...
@@ -166,7 +210,6 @@ static int cli_scanrar(int desc, const char **virname, long int *scanned, const
166 166
 	if((rarlist->item.Flags & 0x03) != 0) {
167 167
 	    cli_dbgmsg("RAR: Skipping %s (splitted)\n", rarlist->item.Name);
168 168
 	    rarlist = rarlist->next;
169
-	    files++;
170 169
 	    continue;
171 170
 	}
172 171
 
... ...
@@ -184,7 +227,6 @@ static int cli_scanrar(int desc, const char **virname, long int *scanned, const
184 184
 	    if(limits->maxfilesize && (rarlist->item.UnpSize > (unsigned int) limits->maxfilesize)) {
185 185
 		cli_dbgmsg("RAR: %s: Size exceeded (%u, max: %lu)\n", rarlist->item.Name, (unsigned int) rarlist->item.UnpSize, limits->maxfilesize);
186 186
 		rarlist = rarlist->next;
187
-		files++;
188 187
 		if(BLOCKMAX) {
189 188
 		    *virname = "RAR.ExceededFileSize";
190 189
 		    ret = CL_VIRUS;
... ...
@@ -206,7 +248,6 @@ static int cli_scanrar(int desc, const char **virname, long int *scanned, const
206 206
 
207 207
         if(rarlist->item.FileAttr & RAR_FENTRY_ATTR_DIRECTORY) {
208 208
             rarlist = rarlist->next;
209
-            files++;
210 209
             continue;
211 210
         }
212 211
 
... ...
@@ -273,7 +314,6 @@ static int cli_scanrar(int desc, const char **virname, long int *scanned, const
273 273
 	fclose(tmp);
274 274
 	tmp = NULL;
275 275
 	rarlist = rarlist->next;
276
-	files++;
277 276
     }
278 277
 
279 278
     urarlib_freelist(rarlist_head);
... ...
@@ -298,7 +338,7 @@ static int cli_scanzip(int desc, const char **virname, long int *scanned, const
298 298
 	char *buff;
299 299
 	int fd, bytes, files = 0, ret = CL_CLEAN, encrypted;
300 300
 	struct stat source;
301
-	struct cli_zip_node *mdata;
301
+	struct cli_meta_node *mdata;
302 302
 	zzip_error_t err;
303 303
 
304 304
 
... ...
@@ -331,7 +371,7 @@ static int cli_scanzip(int desc, const char **virname, long int *scanned, const
331 331
 
332 332
 	encrypted = zdirent.d_flags;
333 333
 
334
-	cli_dbgmsg("Zip: %s, crc32: 0x%x, encrypted: %d, compressed: %u, normal: %u, ratio: %d (max: %d)\n", zdirent.d_name, zdirent.d_crc32, encrypted, zdirent.d_csize, zdirent.st_size, zdirent.d_csize ? (zdirent.st_size / zdirent.d_csize) : 0, limits ? limits->maxratio : -1);
334
+	cli_dbgmsg("Zip: %s, crc32: 0x%x, encrypted: %d, compressed: %u, normal: %u, method: %d, ratio: %d (max: %d)\n", zdirent.d_name, zdirent.d_crc32, encrypted, zdirent.d_csize, zdirent.st_size, zdirent.d_compr, zdirent.d_csize ? (zdirent.st_size / zdirent.d_csize) : 0, limits ? limits->maxratio : -1);
335 335
 
336 336
 	if(!zdirent.st_size) {
337 337
 	    if(zdirent.d_crc32) {
... ...
@@ -358,7 +398,7 @@ static int cli_scanzip(int desc, const char **virname, long int *scanned, const
358 358
 	    if(mdata->size >= 0 && mdata->size != zdirent.st_size)
359 359
 		continue;
360 360
 
361
-	    if(mdata->compr >= 0 && mdata->compr != zdirent.d_compr)
361
+	    if(mdata->method >= 0 && mdata->method != zdirent.d_compr)
362 362
 		continue;
363 363
 
364 364
 	    if(mdata->fileno && mdata->fileno != files)
... ...
@@ -251,7 +251,7 @@ int build(struct optstruct *opt)
251 251
 	exit(1);
252 252
     }
253 253
 
254
-    if(stat("main.db", &foo) == -1 && stat("daily.db", &foo) == -1 && stat("main.hdb", &foo) == -1 && stat("daily.hdb", &foo) == -1 && stat("main.ndb", &foo) == -1 && stat("daily.ndb", &foo) == -1 && stat("main.zmd", &foo) == -1 && stat("daily.zmd", &foo) == -1) {
254
+    if(stat("main.db", &foo) == -1 && stat("daily.db", &foo) == -1 && stat("main.hdb", &foo) == -1 && stat("daily.hdb", &foo) == -1 && stat("main.ndb", &foo) == -1 && stat("daily.ndb", &foo) == -1 && stat("main.zmd", &foo) == -1 && stat("main.rmd", &foo) == -1 && stat("daily.zmd", &foo) == -1 && stat("daily.rmd", &foo) == -1) {
255 255
 	mprintf("Virus database not found in current working directory.\n");
256 256
 	exit(1);
257 257
     }
... ...
@@ -271,7 +271,7 @@ int build(struct optstruct *opt)
271 271
 	mprintf("WARNING: There are no signatures in the database(s).\n");
272 272
     } else {
273 273
 	mprintf("Signatures: %d\n", no);
274
-	realno = countlines("main.db") + countlines("daily.db") + countlines("main.hdb") + countlines("daily.hdb") + countlines("main.ndb") + countlines("daily.ndb") + countlines("main.zmd") + countlines("daily.zmd");
274
+	realno = countlines("main.db") + countlines("daily.db") + countlines("main.hdb") + countlines("daily.hdb") + countlines("main.ndb") + countlines("daily.ndb") + countlines("main.zmd") + countlines("daily.zmd") + countlines("main.rmd") + countlines("daily.rmd");
275 275
 	if(realno != no) {
276 276
 	    mprintf("!Signatures in database: %d. Loaded: %d.\n", realno, no);
277 277
 	    mprintf("Please check the current directory and remove unnecessary databases\n");
... ...
@@ -288,7 +288,7 @@ int build(struct optstruct *opt)
288 288
 	    exit(1);
289 289
 	case 0:
290 290
 	    {
291
-		char *args[] = { "tar", "-cvf", NULL, "COPYING", "main.db", "daily.db", "Notes", "viruses.db3", "main.hdb", "daily.hdb", "main.ndb", "daily.ndb", "main.zmd", "daily.zmd", "main.fp", "daily.fp", NULL };
291
+		char *args[] = { "tar", "-cvf", NULL, "COPYING", "main.db", "daily.db", "Notes", "viruses.db3", "main.hdb", "daily.hdb", "main.ndb", "daily.ndb", "main.zmd", "daily.zmd", "main.rmd", "daily.rmd", "main.fp", "daily.fp", NULL };
292 292
 		args[2] = tarfile;
293 293
 		execv("/bin/tar", args);
294 294
 		mprintf("!Can't execute tar\n");
... ...
@@ -705,7 +705,7 @@ int listdb(const char *filename)
705 705
 	    free(start);
706 706
 	}
707 707
 
708
-    } else if(cli_strbcasestr(filename, ".ndb") || cli_strbcasestr(filename, ".zmd")) {
708
+    } else if(cli_strbcasestr(filename, ".ndb") || cli_strbcasestr(filename, ".zmd") || cli_strbcasestr(filename, ".rmd")) {
709 709
 
710 710
 	while(fgets(buffer, FILEBUFF, fd)) {
711 711
 	    line++;
... ...
@@ -755,6 +755,7 @@ int listdir(const char *dirname)
755 755
 	     cli_strbcasestr(dent->d_name, ".hdb") ||
756 756
 	     cli_strbcasestr(dent->d_name, ".ndb") ||
757 757
 	     cli_strbcasestr(dent->d_name, ".zmd") ||
758
+	     cli_strbcasestr(dent->d_name, ".rmd") ||
758 759
 	     cli_strbcasestr(dent->d_name, ".cvd"))) {
759 760
 
760 761
 		dbfile = (char *) mcalloc(strlen(dent->d_name) + strlen(dirname) + 2, sizeof(char));