Browse code

extract and scan SIS packages

git-svn: trunk@1805

Tomasz Kojm authored on 2006/01/07 12:30:07
Showing 4 changed files
... ...
@@ -1,3 +1,7 @@
1
+Sat Jan  7 04:27:05 CET 2006 (tk)
2
+---------------------------------
3
+  * libclamav/sis.c: extract and scan SIS packages
4
+
1 5
 Mon Jan  2 18:02:20 GMT 2006 (njh)
2 6
 ----------------------------------
3 7
   * libclamav/mbox.c:	Bug fix to the patch of 28/12 for versions of curl
... ...
@@ -105,7 +105,6 @@ extern int cli_mbox(const char *dir, int desc, unsigned int options); /* FIXME *
105 105
 
106 106
 static int cli_scanfile(const char *filename, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, const struct cl_limits *limits, unsigned int options, unsigned int arec, unsigned int mrec);
107 107
 
108
-static int cli_scandir(const char *dirname, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, const struct cl_limits *limits, unsigned int options, unsigned int arec, unsigned int mrec);
109 108
 
110 109
 /*
111 110
 #ifdef CL_THREAD_SAFE
... ...
@@ -842,7 +841,7 @@ static int cli_scanmscab(int desc, const char **virname, unsigned long int *scan
842 842
     return ret;
843 843
 }
844 844
 
845
-static int cli_scandir(const char *dirname, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, const struct cl_limits *limits, unsigned int options, unsigned int arec, unsigned int mrec)
845
+int cli_scandir(const char *dirname, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, const struct cl_limits *limits, unsigned int options, unsigned int arec, unsigned int mrec)
846 846
 {
847 847
 	DIR *dd;
848 848
 	struct dirent *dent;
... ...
@@ -23,4 +23,6 @@
23 23
 
24 24
 int cli_magic_scandesc(int desc, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, const struct cl_limits *limits, unsigned int options, unsigned int arec, unsigned int mrec);
25 25
 
26
+int cli_scandir(const char *dirname, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, const struct cl_limits *limits, unsigned int options, unsigned int arec, unsigned int mrec);
27
+
26 28
 #endif
... ...
@@ -1,5 +1,5 @@
1 1
 /*
2
- *  Copyright (C) 2005 Tomasz Kojm <tkojm@clamav.net>
2
+ *  Copyright (C) 2005 - 2006 Tomasz Kojm <tkojm@clamav.net>
3 3
  *
4 4
  *  This program is free software; you can redistribute it and/or modify
5 5
  *  it under the terms of the GNU General Public License as published by
... ...
@@ -20,6 +20,8 @@
20 20
 #include "clamav-config.h"
21 21
 #endif
22 22
 
23
+#if HAVE_MMAP
24
+
23 25
 #include <stdio.h>
24 26
 #include <string.h>
25 27
 #include <sys/types.h>
... ...
@@ -28,20 +30,21 @@
28 28
 #include <sys/stat.h>
29 29
 #include <unistd.h>
30 30
 #include <time.h>
31
+#include <zlib.h>
31 32
 
32
-#if HAVE_MMAP
33 33
 #if HAVE_SYS_MMAN_H
34 34
 #include <sys/mman.h>
35 35
 #else /* HAVE_SYS_MMAN_H */
36 36
 #undef HAVE_MMAP
37 37
 #endif
38
-#endif
39 38
 
40 39
 #include "cltypes.h"
41 40
 #include "clamav.h"
42 41
 #include "others.h"
43 42
 #include "sis.h"
44 43
 
44
+#define BLOCKMAX		    (options & CL_SCAN_BLOCKMAX)
45
+
45 46
 #if WORDS_BIGENDIAN == 0
46 47
 #define EC16(v)	(v)
47 48
 #define EC32(v) (v)
... ...
@@ -71,15 +74,268 @@ static char *langcodes[] = {
71 71
     "BO", "TI", "CT", "TK", "UK", "UR", "",   "VI", "CY", "ZU"
72 72
 };
73 73
 
74
+#ifndef O_BINARY
75
+#define O_BINARY 0
76
+#endif
77
+
78
+#define SIS_MAX_NAME 512
79
+#define SIS_MAX_SIZE 134217728
80
+
81
+static char *sis_utf16_decode(const char *str, uint32_t length)
82
+{
83
+	char *decoded;
84
+	int i, j;
85
+
86
+
87
+    if(!length || length % 2) {
88
+	cli_warnmsg("SIS: sis_utf16_decode: Broken filename (length == %d)\n", length);
89
+	return NULL;
90
+    }
91
+
92
+    if(!(decoded = cli_calloc(length / 2 + 1, sizeof(char))))
93
+	return NULL;
94
+
95
+    for(i = 0, j = 0; i < length; i += 2, j++) {
96
+       decoded[j] = str[i + 1] << 4;
97
+       decoded[j] += str[i];
98
+       if(decoded[j] == '%')
99
+	   decoded[j] = '_';
100
+    }
101
+
102
+    return decoded;
103
+}
104
+
105
+static int sis_extract_simple(int fd, char *mfile, uint32_t length, uint32_t offset, uint16_t nlangs, uint8_t compressed, const char *dir, const char **virname, const struct cl_limits *limits, unsigned int options)
106
+{
107
+	const char *typedir = NULL;
108
+	char *sname = NULL, *dname = NULL, *subdir, *fname, *buff;
109
+	int desc, i;
110
+	uint8_t get_dname = 1;
111
+	uint32_t namelen, nameoff, filelen, fileoff;
112
+	struct stat sb;
113
+	uLong osize = 0;
114
+	uLongf csize = 0;
115
+
116
+
117
+    if(offset + 24 + 8 * nlangs >= length) {
118
+	cli_errmsg("SIS: sis_extract_simple: Broken file record\n");
119
+	return CL_EFORMAT;
120
+    }
121
+
122
+    switch(cli_readint32(mfile + offset)) {
123
+	case 0x00:
124
+	    cli_dbgmsg("SIS: File type: Standard file\n");
125
+	    typedir = "standard";
126
+	    break;
127
+	case 0x01:
128
+	    cli_dbgmsg("SIS: File type: Text file\n");
129
+	    typedir = "text";
130
+	    get_dname = 0;
131
+	    break;
132
+	case 0x02:
133
+	    cli_dbgmsg("SIS: File type: Component file\n");
134
+	    typedir = "component";
135
+	    break;
136
+	case 0x03:
137
+	    cli_dbgmsg("SIS: File type: Run file\n");
138
+	    typedir = "run";
139
+	    switch(cli_readint32(mfile + offset + 4)) {
140
+		case 0x0000:
141
+		    cli_dbgmsg("SIS:    * During installation only\n");
142
+		    break;
143
+		case 0x0001:
144
+		    cli_dbgmsg("SIS:    * During removal only\n");
145
+		    break;
146
+		case 0x0002:
147
+		    cli_dbgmsg("SIS:    * During installation and removal\n");
148
+		    break;
149
+		case 0x0100:
150
+		    cli_dbgmsg("SIS:    * Ends when installation finished\n");
151
+		    break;
152
+		case 0x0200:
153
+		    cli_dbgmsg("SIS:    * Waits until closed before continuing\n");
154
+		    break;
155
+		default:
156
+		    cli_warnmsg("SIS: sis_extract_simple: Unknown value in file details\n");
157
+	    }
158
+	    break;
159
+	case 0x04:
160
+	    cli_dbgmsg("SIS: File type: Null file\n");
161
+	    break;
162
+	case 0x05:
163
+	    cli_dbgmsg("SIS: File type: MIME file\n");
164
+	    break;
165
+	default:
166
+	    cli_warnmsg("SIS: Unknown file type in file record\n");
167
+    }
168
+
169
+    /* Source name */
170
+    namelen = (uint32_t) cli_readint32(mfile + offset + 8);
171
+    if(namelen > SIS_MAX_NAME) {
172
+	cli_warnmsg("SIS: sis_extract_simple: Source name too long and will not be decoded\n");
173
+    } else {
174
+	nameoff = cli_readint32(mfile + offset + 12);
175
+	if(nameoff >= length ||  nameoff + namelen >= length) {
176
+	    cli_errmsg("SIS: sis_extract_simple: Broken source name data\n");
177
+	    return CL_EFORMAT;
178
+	}
179
+
180
+	if((sname = sis_utf16_decode(mfile + nameoff, namelen)))
181
+	    cli_dbgmsg("SIS: Source name: %s\n", sname);
182
+	else
183
+	    cli_warnmsg("SIS: Source name not decoded\n");
184
+    }
185
+
186
+    /* Destination name */
187
+    if(get_dname) {
188
+	namelen = (uint32_t) cli_readint32(mfile + offset + 16);
189
+	if(namelen > SIS_MAX_NAME) {
190
+	    cli_warnmsg("SIS: sis_extract_simple: Destination name too long and will not be decoded\n");
191
+	} else {
192
+	    nameoff = cli_readint32(mfile + offset + 20);
193
+	    if(nameoff >= length || nameoff + namelen >= length) {
194
+		cli_errmsg("SIS: sis_extract_simple: Broken destination name data\n");
195
+		if(sname)
196
+		    free(sname);
197
+		return CL_EFORMAT;
198
+	    }
199
+
200
+	    if((dname = sis_utf16_decode(mfile + nameoff, namelen)))
201
+		cli_dbgmsg("SIS: Destination name: %s\n", dname);
202
+	    else
203
+		cli_warnmsg("SIS: Destination name not decoded\n");
204
+	}
205
+    }
206
+
207
+    if(!cli_leavetemps_flag) {
208
+	if(sname)
209
+	    free(sname);
210
+	if(dname)
211
+	    free(dname);
212
+    }
213
+
214
+    /* Files */
215
+    if(typedir) {
216
+	if(!(subdir = cli_malloc(strlen(dir) + strlen(typedir) + 2)))
217
+	    return CL_EMEM;
218
+	sprintf(subdir, "%s/%s", dir, typedir);
219
+    } else {
220
+	if(!(subdir = strdup(dir)))
221
+	    return CL_EMEM;
222
+    }
223
+
224
+    if(stat(subdir, &sb) == -1) {
225
+	if(mkdir(subdir, 0700) == -1) {
226
+	    free(subdir);
227
+	    return CL_EIO;
228
+	}
229
+    }
230
+
231
+    for(i = 0; i < nlangs; i++) {
232
+	filelen = cli_readint32(mfile + offset + 24 + 4 * i);
233
+	fileoff = cli_readint32(mfile + offset + 24 + 4 * (i + 1));
234
+
235
+	if(filelen >= length || fileoff >= length || filelen + fileoff > length) {
236
+	    cli_errmsg("SIS: sis_extract_simple: Broken file data (filelen, fileoff)\n");
237
+	    free(subdir);
238
+	    return CL_EFORMAT;
239
+	}
240
+
241
+	if(!(fname = cli_gentemp(subdir))) {
242
+	    free(subdir);
243
+	    return CL_EMEM;
244
+	}
245
+
246
+	if(compressed) {
247
+	    csize = (uLong) filelen;
248
+	    filelen = cli_readint32(mfile + offset + 24 + 8 * (i + 1));
249
+	    osize = (uLongf) filelen;
250
+
251
+	    if(limits && limits->maxfilesize && osize > limits->maxfilesize) {
252
+		cli_dbgmsg("SIS: Size exceeded (%d, max: %ld)\n", osize, limits->maxfilesize);
253
+		if(BLOCKMAX) {
254
+		    *virname = "SIS.ExceededFileSize";
255
+		    free(subdir);
256
+		    free(fname);
257
+		    return CL_VIRUS;
258
+		}
259
+		free(subdir);
260
+		free(fname);
261
+		return CL_EFORMAT;
262
+	    }
263
+
264
+	    if(!(buff = cli_malloc((size_t) osize))) {
265
+		cli_errmsg("SIS: sis_extract_simple: Can't allocate decompression buffer\n");
266
+		free(subdir);
267
+		free(fname);
268
+		return CL_EIO;
269
+	    } 
270
+
271
+	    if(uncompress((Bytef *) buff, &osize , (Bytef *) mfile + fileoff, csize) != Z_OK) {
272
+		cli_errmsg("SIS: sis_extract_simple: File decompression failed\n");
273
+		free(buff);
274
+		free(subdir);
275
+		free(fname);
276
+		return CL_EIO;
277
+	    }
278
+
279
+	} else {
280
+	    buff = mfile + fileoff;
281
+	}
282
+
283
+	if((desc = open(fname, O_CREAT|O_WRONLY|O_TRUNC|O_BINARY, S_IRUSR|S_IWUSR)) == -1) {
284
+	    cli_errmsg("SIS: sis_extract_simple: Can't create new file %s\n", fname);
285
+	    free(subdir);
286
+	    free(fname);
287
+	    if(compressed)
288
+		free(buff);
289
+	    return CL_EIO;
290
+	} 
291
+
292
+	if(cli_writen(desc, buff, filelen) != filelen) {
293
+	    cli_errmsg("SIS: sis_extract_simple: Can't write %d bytes to %s\n", filelen, fname);
294
+	    free(subdir);
295
+	    free(fname);
296
+	    if(compressed)
297
+		free(buff);
298
+	    return CL_EIO;
299
+	} else {
300
+	    if(compressed)
301
+		cli_dbgmsg("SIS: File decompressed into %s\n", fname);
302
+	    else
303
+		cli_dbgmsg("SIS: File saved into %s\n", fname);
304
+	}
305
+
306
+	if(close(desc) == -1) {
307
+	    cli_errmsg("SIS: sis_extract_simple: Can't close descriptor %d\n", filelen, fname);
308
+	    free(subdir);
309
+	    free(fname);
310
+	    if(compressed)
311
+		free(buff);
312
+	    return CL_EIO;
313
+	} 
314
+
315
+	free(fname);
316
+
317
+	if(compressed)
318
+	    free(buff);
319
+    }
320
+
321
+    free(subdir);
322
+    return 0;
323
+}
324
+
74 325
 int cli_scansis(int desc, const char **virname, long int *scanned, const struct cl_engine *engine, const struct cl_limits *limits, unsigned int options, unsigned int arec, unsigned int mrec)
75 326
 {
76 327
 	struct sis_file_hdr file_hdr;
77 328
 	struct sis_file_hdr6 file_hdr6;
78
-	uint8_t release = 0;
79
-	uint16_t opts, nlangs, *langrecs;
80
-	char *mfile = NULL, *langs;
329
+	uint8_t release = 0, compressed;
330
+	uint16_t opts, nlangs, *langrecs, nfiles;
331
+	uint32_t recp, frecord, n;
332
+	size_t length;
333
+	char *mfile = NULL, *langs, *dir;
81 334
 	struct stat sb;
82
-	int i;
335
+	int i, ret;
83 336
 
84 337
 
85 338
     if(fstat(desc, &sb) == -1) {
... ...
@@ -92,31 +348,25 @@ int cli_scansis(int desc, const char **virname, long int *scanned, const struct
92 92
 	return CL_CLEAN;
93 93
     }
94 94
 
95
-#if HAVE_MMAP
96
-    if(sb.st_size < 33554432) {
97
-	mfile = (char *) mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, desc, 0);
95
+    length = sb.st_size;
96
+
97
+    if(length <= SIS_MAX_SIZE) {
98
+	mfile = (char *) mmap(NULL, length, PROT_READ, MAP_PRIVATE, desc, 0);
98 99
 	if(mfile == MAP_FAILED) {
99
-	    mfile = NULL;
100
+	    cli_errmsg("SIS: mmap() failed\n");
101
+	    return CL_EMEM;
100 102
 	} else {
101 103
 	    cli_dbgmsg("SIS: mmap'ed file\n");
102 104
 	    memcpy(&file_hdr, mfile, sizeof(struct sis_file_hdr));
103 105
 	}
104
-    }
105
-#endif
106
-
107
-    if(!mfile) {
108
-	if(read(desc, &file_hdr, sizeof(struct sis_file_hdr)) != sizeof(struct sis_file_hdr)) {
109
-	    cli_dbgmsg("SIS: Can't read file header\n"); /* Not a SIS file? */
110
-	    return CL_CLEAN;
111
-	}
106
+    } else {
107
+	cli_warnmsg("SIS: File too large (> %d)\n", SIS_MAX_SIZE);
108
+	return CL_CLEAN;
112 109
     }
113 110
 
114 111
     if(EC32(file_hdr.uid3) != 0x10000419) {
115 112
 	cli_dbgmsg("SIS: Not a SIS file\n");
116
-#if HAVE_MMAP
117
-	if(mfile)
118
-	    munmap(mfile, sb.st_size);
119
-#endif
113
+	munmap(mfile, length);
120 114
 	return CL_CLEAN;
121 115
     }
122 116
 
... ...
@@ -130,7 +380,9 @@ int cli_scansis(int desc, const char **virname, long int *scanned, const struct
130 130
 	    release = 6;
131 131
 	    break;
132 132
 	default:
133
-	    cli_warnmsg("SIS: Unknown value of UID 2 (EPOC release)\n");
133
+	    cli_warnmsg("SIS: Unknown value of UID 2 (EPOC release) -> not a real SIS file??\n");
134
+	    munmap(mfile, length);
135
+	    return CL_CLEAN;
134 136
     }
135 137
 
136 138
     /* TODO: Verify checksums (uid4 and checksum) */
... ...
@@ -138,38 +390,28 @@ int cli_scansis(int desc, const char **virname, long int *scanned, const struct
138 138
     /* Languages */
139 139
     nlangs = EC16(file_hdr.nlangs);
140 140
     cli_dbgmsg("SIS: Number of languages: %d\n", nlangs);
141
-    cli_dbgmsg("SIS: Offset of languages records: %d\n", EC32(file_hdr.plangs));
142 141
 
143 142
     if(nlangs && nlangs < 100) {
144 143
 
145
-	if(EC32(file_hdr.plangs) + nlangs * 2 >= sb.st_size) {
144
+	if(EC32(file_hdr.plangs) >= length || EC32(file_hdr.plangs) + nlangs * 2 >= sb.st_size) {
146 145
 	    cli_errmsg("SIS: Broken file structure (language records)\n");
147
-#if HAVE_MMAP
148
-	    if(mfile)
149
-		munmap(mfile, sb.st_size);
150
-#endif
146
+	    munmap(mfile, length);
151 147
 	    return CL_EFORMAT;
152 148
 	}
153 149
 
154
-	langrecs = (uint16_t *) cli_malloc(nlangs * 2);
150
+	if(!(langrecs = (uint16_t *) cli_malloc(nlangs * 2))) {
151
+	    munmap(mfile, length);
152
+	    return CL_EMEM;
153
+	}
155 154
 
156
-	if(!mfile) {
157
-	    if(lseek(desc, EC32(file_hdr.plangs), SEEK_SET) < 0) {
158
-		cli_errmsg("SIS: No language records\n");
159
-		free(langrecs);
160
-		return CL_EFORMAT;
161
-	    }
155
+	memcpy(langrecs, mfile + EC32(file_hdr.plangs), nlangs * 2);
162 156
 
163
-	    if(read(desc, langrecs, nlangs * 2) != nlangs * 2) {
164
-		cli_errmsg("SIS: Can't read language records\n");
165
-		free(langrecs);
166
-		return CL_EFORMAT;
167
-	    }
168
-	} else {
169
-	    memcpy(langrecs, mfile + EC32(file_hdr.plangs), nlangs * 2);
157
+	if(!(langs = (char *) cli_calloc(nlangs * 3 + 1, sizeof(char)))) {
158
+	    munmap(mfile, length);
159
+	    free(langrecs);
160
+	    return CL_EMEM;
170 161
 	}
171 162
 
172
-	langs = (char *) cli_calloc(nlangs * 3 + 1, sizeof(char));
173 163
 	for(i = 0; i < nlangs; i++) {
174 164
 	    strncat(langs, langcodes[EC16(langrecs[i]) % 98], 2);
175 165
 	    if(i != nlangs - 1)
... ...
@@ -178,21 +420,22 @@ int cli_scansis(int desc, const char **virname, long int *scanned, const struct
178 178
 	cli_dbgmsg("SIS: Supported languages: %s\n", langs);
179 179
 	free(langrecs);
180 180
 	free(langs);
181
+
182
+    } else  {
183
+	cli_errmsg("SIS: Incorrect number of languages (%d)\n", nlangs);
184
+	munmap(mfile, length);
185
+	return CL_EFORMAT;
181 186
     }
182 187
 
188
+    cli_dbgmsg("SIS: Offset of languages records: %d\n", EC32(file_hdr.plangs));
189
+
183 190
     if(EC16(file_hdr.ilang))
184 191
 	cli_dbgmsg("SIS: Installation language: %d\n", EC16(file_hdr.ilang));
185 192
 
186
-    /* Files */
187
-    cli_dbgmsg("SIS: Number of files: %d\n", EC16(file_hdr.nfiles));
188
-    cli_dbgmsg("SIS: Offset of files records: %d\n", EC32(file_hdr.pfiles));
189
-
190
-
191 193
     /* Requisites */
192 194
     cli_dbgmsg("SIS: Number of requisites: %d\n", EC16(file_hdr.nreqs));
193 195
     cli_dbgmsg("SIS: Offset of requisites records: %d\n", EC32(file_hdr.preqs));
194 196
 
195
-
196 197
     /* Options flags */
197 198
     opts = EC16(file_hdr.options);
198 199
     cli_dbgmsg("SIS: Options:\n");
... ...
@@ -200,10 +443,13 @@ int cli_scansis(int desc, const char **virname, long int *scanned, const struct
200 200
 	cli_dbgmsg("SIS:    * File is in Unicode format\n");
201 201
     if(opts & 0x0002)
202 202
 	cli_dbgmsg("SIS:    * File is distributable\n");
203
-    if(opts & 0x0008)
203
+    if(opts & 0x0008) {
204 204
 	cli_dbgmsg("SIS:    * Packed files are not compressed\n");
205
-    else
205
+	compressed = 0;
206
+    } else {
206 207
 	cli_dbgmsg("SIS:    * Packed files are compressed\n");
208
+	compressed = 1;
209
+    }
207 210
     if(opts & 0x0010)
208 211
 	cli_dbgmsg("SIS:    * File installation shuts down all applications\n");
209 212
 
... ...
@@ -236,33 +482,174 @@ int cli_scansis(int desc, const char **virname, long int *scanned, const struct
236 236
 
237 237
     if(release == 6) {
238 238
 
239
-	if(sizeof(struct sis_file_hdr) + sizeof(struct sis_file_hdr6) >= sb.st_size) {
239
+	if(sizeof(struct sis_file_hdr) + sizeof(struct sis_file_hdr6) >= length) {
240 240
 	    cli_errmsg("SIS: Broken file structure (language records)\n");
241
-#if HAVE_MMAP
242
-	    if(mfile)
243
-		munmap(mfile, sb.st_size);
244
-#endif
241
+	    munmap(mfile, length);
245 242
 	    return CL_EFORMAT;
246 243
 	}
247 244
 
245
+	memcpy(&file_hdr6, mfile + sizeof(struct sis_file_hdr), sizeof(struct sis_file_hdr6));
246
+	cli_dbgmsg("SIS: Maximum space required: %d\n", EC32(file_hdr6.maxispace));
247
+    }
248
+
249
+    /* Files */
250
+    nfiles = EC16(file_hdr.nfiles);
251
+
252
+    if(limits && limits->maxfiles && nfiles > limits->maxfiles) {
253
+	cli_dbgmsg("SIS: Files limit reached (max: %d)\n", limits->maxfiles);
254
+	if(BLOCKMAX) {
255
+	    *virname = "SIS.ExceededFilesLimit";
256
+	    munmap(mfile, length);
257
+	    return CL_VIRUS;
258
+	}
259
+	return CL_CLEAN;
260
+    }
261
+
262
+    cli_dbgmsg("SIS: Number of files: %d\n", nfiles);
263
+    cli_dbgmsg("SIS: Offset of files records: %d\n", EC32(file_hdr.pfiles));
248 264
 
249
-	if(!mfile) {
250
-	    lseek(desc, sizeof(struct sis_file_hdr), SEEK_SET);
265
+    if(!(dir = cli_gentempdir(NULL))) {
266
+	cli_errmsg("SIS: Can't generate temporary directory\n");
267
+	munmap(mfile, length);
268
+	return CL_ETMPDIR;
269
+    }
251 270
 
252
-	    if(read(desc, &file_hdr6, sizeof(struct sis_file_hdr6)) != sizeof(struct sis_file_hdr6)) {
253
-		cli_dbgmsg("SIS: Can't read additional data of EPOC 6 file header\n"); /* Not a SIS file? */
254
-		return CL_EFORMAT;
255
-	    }
256
-	} else {
257
-	    memcpy(&file_hdr6, mfile + sizeof(struct sis_file_hdr), sizeof(struct sis_file_hdr6));
271
+    if((frecord = EC32(file_hdr.pfiles)) >= length) {
272
+	cli_errmsg("SIS: Broken file structure (frecord)\n");
273
+	munmap(mfile, length);
274
+	free(dir);
275
+	return CL_EFORMAT;
276
+    }
277
+
278
+    for(i = 0; i < nfiles; i++) {
279
+
280
+	cli_dbgmsg("SIS: -----\n");
281
+
282
+	if(frecord + 4 >= length) {
283
+	    cli_errmsg("SIS: Broken file structure (frecord)\n");
284
+	    munmap(mfile, length);
285
+	    if(!cli_leavetemps_flag)
286
+		cli_rmdirs(dir);
287
+	    free(dir);
288
+	    return CL_EFORMAT;
289
+	}
290
+
291
+	switch(cli_readint32(mfile + frecord)) {
292
+	    case 0x00000000:
293
+		cli_dbgmsg("SIS: Simple file record\n");
294
+		if((ret = sis_extract_simple(desc, mfile, sb.st_size, frecord + 4, nlangs, compressed, dir, virname, limits, options))) {
295
+		    munmap(mfile, length);
296
+		    if(!cli_leavetemps_flag)
297
+			cli_rmdirs(dir);
298
+		    free(dir);
299
+		    return ret;
300
+		}
301
+
302
+		if(release == 6)
303
+		    frecord += 32 + 12 * nlangs + 4;
304
+		else
305
+		    frecord += 28 + 4 * nlangs + 4;
306
+
307
+		break;
308
+	    case 0x00000001:
309
+		cli_dbgmsg("SIS: Multiple languages file record\n");
310
+		/* TODO: Pass language strings into sis_extract */
311
+		if((ret = sis_extract_simple(desc, mfile, sb.st_size, frecord + 4, nlangs, compressed, dir, virname, limits, options))) {
312
+		    munmap(mfile, length);
313
+		    if(!cli_leavetemps_flag)
314
+			cli_rmdirs(dir);
315
+		    free(dir);
316
+		    return ret;
317
+		}
318
+
319
+		if(release == 6)
320
+		    frecord += 32 + 12 * nlangs + 4;
321
+		else
322
+		    frecord += 28 + 4 * nlangs + 4;
323
+
324
+		break;
325
+	    case 0x00000002:
326
+		cli_dbgmsg("SIS: Options record\n");
327
+		if(frecord + 8 >= length) {
328
+		    munmap(mfile, length);
329
+		    if(!cli_leavetemps_flag)
330
+			cli_rmdirs(dir);
331
+		    free(dir);
332
+		    return CL_EFORMAT;
333
+		}
334
+
335
+		n = cli_readint32(mfile + frecord + 4);
336
+		cli_dbgmsg("SIS: Number of options: %d\n", n);
337
+
338
+		if(n > 128 || frecord + 8 * n * nlangs >= length) {
339
+		    cli_errmsg("SIS: Incorrect number of options\n");
340
+		    munmap(mfile, length);
341
+		    if(!cli_leavetemps_flag)
342
+			cli_rmdirs(dir);
343
+		    free(dir);
344
+		    return CL_EFORMAT;
345
+		}
346
+
347
+		frecord += 8 + 8 * n * nlangs + 16;
348
+
349
+		break;
350
+	    case 0x00000003:
351
+	    case 0x00000004:
352
+		cli_dbgmsg("SIS: If/ElseIf record\n");
353
+		if(frecord + 8 >= length) {
354
+		    munmap(mfile, length);
355
+		    if(!cli_leavetemps_flag)
356
+			cli_rmdirs(dir);
357
+		    free(dir);
358
+		    return CL_EFORMAT;
359
+		}
360
+
361
+		n = cli_readint32(mfile + frecord + 4);
362
+		cli_dbgmsg("SIS: Size of conditional expression: %d\n", n);
363
+
364
+		if(n >= length) {
365
+		    cli_errmsg("SIS: Incorrect size of conditional expression\n");
366
+		    munmap(mfile, length);
367
+		    if(!cli_leavetemps_flag)
368
+			cli_rmdirs(dir);
369
+		    free(dir);
370
+		    return CL_EFORMAT;
371
+		}
372
+
373
+		frecord += 8 + n;
374
+		break;
375
+	    case 0x00000005:
376
+		cli_dbgmsg("SIS: Else record\n");
377
+		frecord += 4;
378
+		break;
379
+	    case 0x00000006:
380
+		cli_dbgmsg("SIS: EndIf record\n");
381
+		frecord += 4;
382
+		break;
383
+	    default:
384
+		cli_warnmsg("SIS: Unknown file record type\n");
258 385
 	}
259
-	cli_dbgmsg("SIS: Maximum space required: %d\n", EC32(file_hdr6.maxispace));
260 386
     }
261 387
 
262
-#if HAVE_MMAP
263
-    if(mfile)
264
-	munmap(mfile, sb.st_size);
265
-#endif
388
+    /* scan extracted files */
389
+    cli_dbgmsg("SIS:  ****** Scanning extracted files ******\n");
390
+    ret = cli_scandir(dir, virname, scanned, engine, limits, options, arec, mrec);
391
+
392
+    if(!cli_leavetemps_flag)
393
+	cli_rmdirs(dir);
266 394
 
395
+    free(dir);
396
+    munmap(mfile, length);
397
+
398
+    return CL_CLEAN;
399
+}
400
+
401
+#else /* HAVE_MMAP */
402
+
403
+int cli_scansis(int desc, const char **virname, long int *scanned, const struct cl_engine *engine, const struct cl_limits *limits, unsigned int options, unsigned int arec, unsigned int mrec)
404
+{
405
+    cli_warnmsg("Support for SIS files not compiled in!\n");
267 406
     return CL_CLEAN;
268 407
 }
408
+
409
+#endif /* HAVE_MMAP */