git-svn: trunk@2615
Tomasz Kojm authored on 2007/01/13 09:01:39... | ... |
@@ -1,3 +1,8 @@ |
1 |
+Sat Jan 13 00:59:01 CET 2007 (tk) |
|
2 |
+--------------------------------- |
|
3 |
+ * libclamav: extract and scan RAR archives file-by-file (bb#141) |
|
4 |
+ Patch from Edwin |
|
5 |
+ |
|
1 | 6 |
Fri Jan 12 22:03:53 CET 2007 (acab) |
2 | 7 |
----------------------------------- |
3 | 8 |
* libclamav/mew: Cleanup. Now fully merged. |
... | ... |
@@ -16,6 +21,7 @@ Fri Jan 12 18:51:33 CET 2007 (acab) |
16 | 16 |
* libclamav: add MEW support from Michal Spadlinski <gim913 * gmail.com> |
17 | 17 |
Part of the Google Summer of Code program |
18 | 18 |
|
19 |
+>>>>>>> 1.1692 |
|
19 | 20 |
Fri Jan 12 18:35:02 CET 2007 (tk) |
20 | 21 |
--------------------------------- |
21 | 22 |
* libclamav/phishcheck.c: add img url link-type filtering (patch from Edwin) |
... | ... |
@@ -118,149 +118,177 @@ extern short cli_leavetemps_flag; |
118 | 118 |
|
119 | 119 |
static int cli_scanfile(const char *filename, cli_ctx *ctx); |
120 | 120 |
|
121 |
-static int cli_scanrar(int desc, cli_ctx *ctx, off_t sfx_offset, uint32_t *sfx_check) |
|
121 |
+static int cli_unrar_scanmetadata(int desc, rar_metadata_t *metadata, cli_ctx *ctx, unsigned int files, uint32_t* sfx_check) |
|
122 | 122 |
{ |
123 |
- int ret = CL_CLEAN; |
|
124 |
- unsigned int files = 0; |
|
125 |
- rar_metadata_t *metadata, *metadata_tmp; |
|
126 |
- struct cli_meta_node *mdata; |
|
127 |
- char *dir; |
|
128 |
- |
|
123 |
+ int ret = CL_SUCCESS; |
|
124 |
+ struct cli_meta_node* mdata; |
|
129 | 125 |
|
130 |
- cli_dbgmsg("in scanrar()\n"); |
|
131 | 126 |
|
132 |
- /* generate the temporary directory */ |
|
133 |
- dir = cli_gentemp(NULL); |
|
134 |
- if(mkdir(dir, 0700)) { |
|
135 |
- cli_dbgmsg("RAR: Can't create temporary directory %s\n", dir); |
|
136 |
- free(dir); |
|
137 |
- return CL_ETMPDIR; |
|
127 |
+ if(files == 1 && sfx_check) { |
|
128 |
+ if(*sfx_check == metadata->crc) |
|
129 |
+ return CL_BREAK;/* break extract loop */ |
|
130 |
+ else |
|
131 |
+ *sfx_check = metadata->crc; |
|
138 | 132 |
} |
139 | 133 |
|
140 |
- if(sfx_offset) |
|
141 |
- lseek(desc, sfx_offset, SEEK_SET); |
|
142 |
- |
|
143 |
- metadata = metadata_tmp = cli_unrar(desc, dir, ctx->limits); |
|
144 |
- |
|
145 |
- if(cli_scandir(dir, ctx) == CL_VIRUS) { |
|
146 |
- ret = CL_VIRUS; |
|
147 |
- } else while(metadata) { |
|
148 |
- |
|
149 |
- files++; |
|
134 |
+ cli_dbgmsg("RAR: %s, crc32: 0x%x, encrypted: %d, compressed: %u, normal: %u, method: %d, ratio: %d (max: %d)\n", |
|
135 |
+ metadata->filename, metadata->crc, metadata->encrypted, metadata->pack_size, |
|
136 |
+ metadata->unpack_size, metadata->method, |
|
137 |
+ metadata->pack_size ? ((unsigned int) metadata->unpack_size / (unsigned int) metadata->pack_size) : 0, ctx->limits ? ctx->limits->maxratio : 0); |
|
150 | 138 |
|
151 |
- if(files == 1 && sfx_check) { |
|
152 |
- if(*sfx_check == metadata->crc) |
|
153 |
- break; |
|
154 |
- else |
|
155 |
- *sfx_check = metadata->crc; |
|
156 |
- } |
|
157 |
- |
|
158 |
- cli_dbgmsg("RAR: %s, crc32: 0x%x, encrypted: %d, compressed: %u, normal: %u, method: %d, ratio: %d (max: %d)\n", |
|
159 |
- metadata->filename, metadata->crc, metadata->encrypted, metadata->pack_size, |
|
160 |
- metadata->unpack_size, metadata->method, |
|
161 |
- metadata->pack_size ? ((unsigned int) metadata->unpack_size / (unsigned int) metadata->pack_size) : 0, ctx->limits ? ctx->limits->maxratio : 0); |
|
139 |
+ /* Scan metadata */ |
|
140 |
+ mdata = ctx->engine->rar_mlist; |
|
141 |
+ if(mdata) do { |
|
142 |
+ if(mdata->encrypted != metadata->encrypted) |
|
143 |
+ continue; |
|
162 | 144 |
|
163 |
- /* Scan metadata */ |
|
164 |
- mdata = ctx->engine->rar_mlist; |
|
165 |
- if(mdata) do { |
|
166 |
- if(mdata->encrypted != metadata->encrypted) |
|
167 |
- continue; |
|
145 |
+ if(mdata->crc32 && (unsigned int) mdata->crc32 != metadata->crc) |
|
146 |
+ continue; |
|
168 | 147 |
|
169 |
- if(mdata->crc32 && (unsigned int) mdata->crc32 != metadata->crc) |
|
170 |
- continue; |
|
148 |
+ if(mdata->csize > 0 && (unsigned int) mdata->csize != metadata->pack_size) |
|
149 |
+ continue; |
|
171 | 150 |
|
172 |
- if(mdata->csize > 0 && (unsigned int) mdata->csize != metadata->pack_size) |
|
173 |
- continue; |
|
151 |
+ if(mdata->size >= 0 && (unsigned int) mdata->size != metadata->unpack_size) |
|
152 |
+ continue; |
|
174 | 153 |
|
175 |
- if(mdata->size >= 0 && (unsigned int) mdata->size != metadata->unpack_size) |
|
176 |
- continue; |
|
154 |
+ if(mdata->method >= 0 && mdata->method != metadata->method) |
|
155 |
+ continue; |
|
177 | 156 |
|
178 |
- if(mdata->method >= 0 && mdata->method != metadata->method) |
|
179 |
- continue; |
|
157 |
+ if(mdata->fileno && mdata->fileno != files) |
|
158 |
+ continue; |
|
180 | 159 |
|
181 |
- if(mdata->fileno && mdata->fileno != files) |
|
182 |
- continue; |
|
160 |
+ if(mdata->maxdepth && ctx->arec > mdata->maxdepth) |
|
161 |
+ continue; |
|
183 | 162 |
|
184 |
- if(mdata->maxdepth && ctx->arec > mdata->maxdepth) |
|
185 |
- continue; |
|
163 |
+ /* TODO add support for regex */ |
|
164 |
+ /*if(mdata->filename && !strstr(zdirent.d_name, mdata->filename))*/ |
|
165 |
+ if(mdata->filename && strcmp((char *) metadata->filename, mdata->filename)) |
|
166 |
+ continue; |
|
186 | 167 |
|
187 |
- /* TODO add support for regex */ |
|
188 |
- /*if(mdata->filename && !strstr(zdirent.d_name, mdata->filename))*/ |
|
189 |
- if(mdata->filename && strcmp((char *) metadata->filename, mdata->filename)) |
|
190 |
- continue; |
|
168 |
+ break; /* matched */ |
|
191 | 169 |
|
192 |
- break; /* matched */ |
|
170 |
+ } while((mdata = mdata->next)); |
|
193 | 171 |
|
194 |
- } while((mdata = mdata->next)); |
|
172 |
+ if(mdata) { |
|
173 |
+ *ctx->virname = mdata->virname; |
|
174 |
+ return CL_VIRUS; |
|
175 |
+ } |
|
195 | 176 |
|
196 |
- if(mdata) { |
|
197 |
- *ctx->virname = mdata->virname; |
|
198 |
- ret = CL_VIRUS; |
|
199 |
- break; |
|
177 |
+ if(DETECT_ENCRYPTED && metadata->encrypted) { |
|
178 |
+ cli_dbgmsg("RAR: Encrypted files found in archive.\n"); |
|
179 |
+ lseek(desc, 0, SEEK_SET); |
|
180 |
+ ret = cli_scandesc(desc, ctx, 0, 0, 0, NULL); |
|
181 |
+ if(ret != CL_VIRUS) { |
|
182 |
+ *ctx->virname = "Encrypted.RAR"; |
|
183 |
+ return CL_VIRUS; |
|
200 | 184 |
} |
185 |
+ } |
|
201 | 186 |
|
202 |
- if(DETECT_ENCRYPTED && metadata->encrypted) { |
|
203 |
- cli_dbgmsg("RAR: Encrypted files found in archive.\n"); |
|
204 |
- lseek(desc, 0, SEEK_SET); |
|
205 |
- ret = cli_scandesc(desc, ctx, 0, 0, 0, NULL); |
|
206 |
- if(ret < 0) { |
|
207 |
- break; |
|
208 |
- } else if(ret != CL_VIRUS) { |
|
209 |
- *ctx->virname = "Encrypted.RAR"; |
|
210 |
- ret = CL_VIRUS; |
|
187 |
+/* |
|
188 |
+ TROG - TODO: multi-volume files |
|
189 |
+ if((rarlist->item.Flags & 0x03) != 0) { |
|
190 |
+ cli_dbgmsg("RAR: Skipping %s (split)\n", rarlist->item.Name); |
|
191 |
+ rarlist = rarlist->next; |
|
192 |
+ continue; |
|
193 |
+ } |
|
194 |
+*/ |
|
195 |
+ if(ctx->limits) { |
|
196 |
+ if(ctx->limits->maxratio && metadata->unpack_size && metadata->pack_size) { |
|
197 |
+ if((unsigned int) metadata->unpack_size / (unsigned int) metadata->pack_size >= ctx->limits->maxratio) { |
|
198 |
+ cli_dbgmsg("RAR: Max ratio reached (normal: %u, compressed: %u, max: %ld)\n", metadata->unpack_size, metadata->pack_size, ctx->limits->maxratio); |
|
199 |
+ *ctx->virname = "Oversized.RAR"; |
|
200 |
+ return CL_VIRUS; |
|
211 | 201 |
} |
212 |
- break; |
|
213 | 202 |
} |
214 | 203 |
|
215 |
-/* |
|
216 |
- TROG - TODO: multi-volume files |
|
217 |
- if((rarlist->item.Flags & 0x03) != 0) { |
|
218 |
- cli_dbgmsg("RAR: Skipping %s (split)\n", rarlist->item.Name); |
|
219 |
- rarlist = rarlist->next; |
|
220 |
- continue; |
|
221 |
- } |
|
222 |
-*/ |
|
223 |
- if(ctx->limits) { |
|
224 |
- if(ctx->limits->maxratio && metadata->unpack_size && metadata->pack_size) { |
|
225 |
- if((unsigned int) metadata->unpack_size / (unsigned int) metadata->pack_size >= ctx->limits->maxratio) { |
|
226 |
- cli_dbgmsg("RAR: Max ratio reached (normal: %u, compressed: %u, max: %ld)\n", metadata->unpack_size, |
|
227 |
- metadata->pack_size, ctx->limits->maxratio); |
|
228 |
- *ctx->virname = "Oversized.RAR"; |
|
229 |
- ret = CL_VIRUS; |
|
230 |
- break; |
|
231 |
- } |
|
204 |
+ if(ctx->limits->maxfilesize && (metadata->unpack_size > ctx->limits->maxfilesize)) { |
|
205 |
+ cli_dbgmsg("RAR: %s: Size exceeded (%u, max: %lu)\n", metadata->filename, metadata->unpack_size, ctx->limits->maxfilesize); |
|
206 |
+ if(BLOCKMAX) { |
|
207 |
+ *ctx->virname = "RAR.ExceededFileSize"; |
|
208 |
+ return CL_VIRUS; |
|
232 | 209 |
} |
210 |
+ return CL_SUCCESS; |
|
211 |
+ } |
|
233 | 212 |
|
234 |
- if(ctx->limits->maxfilesize && (metadata->unpack_size > (unsigned int) ctx->limits->maxfilesize)) { |
|
235 |
- cli_dbgmsg("RAR: %s: Size exceeded (%u, max: %lu)\n", metadata->filename, |
|
236 |
- metadata->unpack_size, ctx->limits->maxfilesize); |
|
237 |
- if(BLOCKMAX) { |
|
238 |
- *ctx->virname = "RAR.ExceededFileSize"; |
|
239 |
- ret = CL_VIRUS; |
|
240 |
- break; |
|
241 |
- } |
|
242 |
- metadata = metadata->next; |
|
243 |
- continue; |
|
213 |
+ if(ctx->limits->maxfiles && (files > ctx->limits->maxfiles)) { |
|
214 |
+ cli_dbgmsg("RAR: Files limit reached (max: %d)\n", ctx->limits->maxfiles); |
|
215 |
+ if(BLOCKMAX) { |
|
216 |
+ *ctx->virname = "RAR.ExceededFilesLimit"; |
|
217 |
+ return CL_VIRUS; |
|
244 | 218 |
} |
219 |
+ return CL_BREAK; |
|
220 |
+ } |
|
221 |
+ } |
|
245 | 222 |
|
246 |
- if(ctx->limits->maxfiles && (files > ctx->limits->maxfiles)) { |
|
247 |
- cli_dbgmsg("RAR: Files limit reached (max: %d)\n", ctx->limits->maxfiles); |
|
248 |
- if(BLOCKMAX) { |
|
249 |
- *ctx->virname = "RAR.ExceededFilesLimit"; |
|
250 |
- ret = CL_VIRUS; |
|
251 |
- break; |
|
252 |
- } |
|
223 |
+ return ret; |
|
224 |
+} |
|
225 |
+ |
|
226 |
+static int cli_scanrar(int desc, cli_ctx *ctx, off_t sfx_offset, uint32_t *sfx_check) |
|
227 |
+{ |
|
228 |
+ int ret = CL_CLEAN; |
|
229 |
+ unsigned int files = 0; |
|
230 |
+ rar_metadata_t *metadata, *metadata_tmp; |
|
231 |
+ char *dir; |
|
232 |
+ rar_state_t rar_state; |
|
233 |
+ |
|
234 |
+ |
|
235 |
+ cli_dbgmsg("in scanrar()\n"); |
|
236 |
+ |
|
237 |
+ /* generate the temporary directory */ |
|
238 |
+ dir = cli_gentemp(NULL); |
|
239 |
+ if(mkdir(dir, 0700)) { |
|
240 |
+ cli_dbgmsg("RAR: Can't create temporary directory %s\n", dir); |
|
241 |
+ free(dir); |
|
242 |
+ return CL_ETMPDIR; |
|
243 |
+ } |
|
244 |
+ |
|
245 |
+ if(sfx_offset) |
|
246 |
+ lseek(desc, sfx_offset, SEEK_SET); |
|
247 |
+ |
|
248 |
+ if((ret = cli_unrar_open(desc, dir, &rar_state)) != CL_SUCCESS) { |
|
249 |
+ if(!cli_leavetemps_flag) |
|
250 |
+ cli_rmdirs(dir); |
|
251 |
+ free(dir); |
|
252 |
+ cli_dbgmsg("RAR: Error: %s\n", cl_strerror(ret)); |
|
253 |
+ return ret; |
|
254 |
+ } |
|
255 |
+ |
|
256 |
+ do { |
|
257 |
+ int rc; |
|
258 |
+ rar_state.unpack_data->ofd = -1; |
|
259 |
+ ret = cli_unrar_extract_next(&rar_state,dir); |
|
260 |
+ if(rar_state.unpack_data->ofd > 0) { |
|
261 |
+ lseek(rar_state.unpack_data->ofd,0,SEEK_SET); |
|
262 |
+ rc = cli_magic_scandesc(rar_state.unpack_data->ofd,ctx); |
|
263 |
+ close(rar_state.unpack_data->ofd); |
|
264 |
+ if(!cli_leavetemps_flag) |
|
265 |
+ unlink(rar_state.filename); |
|
266 |
+ if(rc == CL_VIRUS ) { |
|
267 |
+ cli_dbgmsg("RAR: infected with %s\n",*ctx->virname); |
|
268 |
+ ret = CL_VIRUS; |
|
253 | 269 |
break; |
254 | 270 |
} |
255 | 271 |
} |
256 | 272 |
|
257 |
- metadata = metadata->next; |
|
258 |
- } |
|
273 |
+ if(ret == CL_SUCCESS) |
|
274 |
+ ret = cli_unrar_scanmetadata(desc,rar_state.metadata, ctx, rar_state.file_count, sfx_check); |
|
275 |
+ |
|
276 |
+ } while(ret == CL_SUCCESS); |
|
277 |
+ |
|
278 |
+ if(ret == CL_BREAK) |
|
279 |
+ ret = CL_CLEAN; |
|
280 |
+ |
|
281 |
+ cli_unrar_close(&rar_state); |
|
282 |
+ metadata = metadata_tmp = rar_state.metadata; |
|
283 |
+ |
|
284 |
+ if(cli_scandir(rar_state.comment_dir, ctx) == CL_VIRUS) |
|
285 |
+ ret = CL_VIRUS; |
|
259 | 286 |
|
260 | 287 |
if(!cli_leavetemps_flag) |
261 | 288 |
cli_rmdirs(dir); |
262 | 289 |
|
263 | 290 |
free(dir); |
291 |
+ |
|
264 | 292 |
metadata = metadata_tmp; |
265 | 293 |
while (metadata) { |
266 | 294 |
metadata_tmp = metadata->next; |
... | ... |
@@ -1381,25 +1381,25 @@ static int rar_unpack(int fd, int method, int solid, unpack_data_t *unpack_data) |
1381 | 1381 |
return retval; |
1382 | 1382 |
} |
1383 | 1383 |
|
1384 |
-rar_metadata_t *cli_unrar(int fd, const char *dirname, const struct cl_limits *limits) |
|
1384 |
+int cli_unrar_open(int fd, const char *dirname, rar_state_t* state) |
|
1385 | 1385 |
{ |
1386 |
- main_header_t *main_hdr; |
|
1387 | 1386 |
int ofd, retval; |
1388 |
- unsigned long file_count=1; |
|
1389 |
- file_header_t *file_header; |
|
1390 | 1387 |
unsigned char filename[1024]; |
1391 | 1388 |
unpack_data_t *unpack_data; |
1392 |
- rar_metadata_t *metadata=NULL, *metadata_tail=NULL, *new_metadata; |
|
1389 |
+ main_header_t *main_hdr; |
|
1393 | 1390 |
off_t offset; |
1394 | 1391 |
|
1395 | 1392 |
cli_dbgmsg("in cli_unrar\n"); |
1393 |
+ if(!state) { |
|
1394 |
+ return CL_ENULLARG; |
|
1395 |
+ } |
|
1396 | 1396 |
if (!is_rar_archive(fd)) { |
1397 |
- return FALSE; |
|
1397 |
+ return CL_EFORMAT; |
|
1398 | 1398 |
} |
1399 | 1399 |
unpack_data = cli_malloc(sizeof(unpack_data_t)); |
1400 | 1400 |
if(!unpack_data) { |
1401 | 1401 |
cli_dbgmsg("unrar: cli_unrar: cli_malloc failed for unpack_data\n"); |
1402 |
- return FALSE; |
|
1402 |
+ return CL_EMEM; |
|
1403 | 1403 |
} |
1404 | 1404 |
unpack_data->rarvm_data.mem = NULL; |
1405 | 1405 |
unpack_data->old_filter_lengths = NULL; |
... | ... |
@@ -1416,12 +1416,33 @@ rar_metadata_t *cli_unrar(int fd, const char *dirname, const struct cl_limits *l |
1416 | 1416 |
init_filters(unpack_data); |
1417 | 1417 |
unpack_free_data(unpack_data); |
1418 | 1418 |
free(unpack_data); |
1419 |
- return metadata; |
|
1419 |
+ return CL_ERAR; |
|
1420 | 1420 |
} |
1421 | 1421 |
cli_dbgmsg("Head CRC: %.4x\n", main_hdr->head_crc); |
1422 | 1422 |
cli_dbgmsg("Head Type: %.2x\n", main_hdr->head_type); |
1423 | 1423 |
cli_dbgmsg("Flags: %.4x\n", main_hdr->flags); |
1424 | 1424 |
cli_dbgmsg("Head Size: %.4x\n", main_hdr->head_size); |
1425 |
+ |
|
1426 |
+ snprintf(filename,1024,"%s/comments",dirname); |
|
1427 |
+ if(mkdir(filename,0700)) { |
|
1428 |
+ cli_dbgmsg("cli_unrar: Unable to create comment temporary directory\n"); |
|
1429 |
+ free(main_hdr); |
|
1430 |
+ ppm_destructor(&unpack_data->ppm_data); |
|
1431 |
+ init_filters(unpack_data); |
|
1432 |
+ unpack_free_data(unpack_data); |
|
1433 |
+ free(unpack_data); |
|
1434 |
+ return CL_ETMPDIR; |
|
1435 |
+ } |
|
1436 |
+ state->comment_dir = cli_strdup(filename); |
|
1437 |
+ if(!state->comment_dir) { |
|
1438 |
+ free(main_hdr); |
|
1439 |
+ ppm_destructor(&unpack_data->ppm_data); |
|
1440 |
+ init_filters(unpack_data); |
|
1441 |
+ unpack_free_data(unpack_data); |
|
1442 |
+ free(unpack_data); |
|
1443 |
+ return CL_EMEM; |
|
1444 |
+ } |
|
1445 |
+ |
|
1425 | 1446 |
if ((main_hdr->flags & MHD_VOLUME) != 0) { |
1426 | 1447 |
/* Part of a RAR VOLUME - Skip it */ |
1427 | 1448 |
cli_dbgmsg("RAR MUTIPART VOLUME - Skippng.\n"); |
... | ... |
@@ -1430,7 +1451,8 @@ rar_metadata_t *cli_unrar(int fd, const char *dirname, const struct cl_limits *l |
1430 | 1430 |
init_filters(unpack_data); |
1431 | 1431 |
unpack_free_data(unpack_data); |
1432 | 1432 |
free(unpack_data); |
1433 |
- return metadata; |
|
1433 |
+ free(state->comment_dir); |
|
1434 |
+ return CL_ESUPPORT; |
|
1434 | 1435 |
} |
1435 | 1436 |
|
1436 | 1437 |
if (main_hdr->head_size < SIZEOF_NEWMHD) { |
... | ... |
@@ -1439,7 +1461,8 @@ rar_metadata_t *cli_unrar(int fd, const char *dirname, const struct cl_limits *l |
1439 | 1439 |
init_filters(unpack_data); |
1440 | 1440 |
unpack_free_data(unpack_data); |
1441 | 1441 |
free(unpack_data); |
1442 |
- return metadata; |
|
1442 |
+ free(state->comment_dir); |
|
1443 |
+ return CL_EFORMAT; |
|
1443 | 1444 |
} |
1444 | 1445 |
if (main_hdr->flags & MHD_COMMENT) { |
1445 | 1446 |
comment_header_t *comment_header; |
... | ... |
@@ -1453,11 +1476,18 @@ rar_metadata_t *cli_unrar(int fd, const char *dirname, const struct cl_limits *l |
1453 | 1453 |
cli_dbgmsg("UnPack Size: 0x%.4x\n", comment_header->unpack_size); |
1454 | 1454 |
cli_dbgmsg("UnPack Version: 0x%.2x\n", comment_header->unpack_ver); |
1455 | 1455 |
cli_dbgmsg("Pack Method: 0x%.2x\n", comment_header->method); |
1456 |
- snprintf(filename, 1024, "%s/main.cmt", dirname); |
|
1456 |
+ snprintf(filename, 1024, "%s/main.cmt", state->comment_dir); |
|
1457 | 1457 |
ofd = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0600); |
1458 | 1458 |
if (ofd < 0) { |
1459 | 1459 |
free(comment_header); |
1460 | 1460 |
cli_dbgmsg("ERROR: Failed to open output file\n"); |
1461 |
+ free(main_hdr); |
|
1462 |
+ ppm_destructor(&unpack_data->ppm_data); |
|
1463 |
+ init_filters(unpack_data); |
|
1464 |
+ unpack_free_data(unpack_data); |
|
1465 |
+ free(unpack_data); |
|
1466 |
+ free(state->comment_dir); |
|
1467 |
+ return CL_EIO; |
|
1461 | 1468 |
} else { |
1462 | 1469 |
if (comment_header->method == 0x30) { |
1463 | 1470 |
cli_dbgmsg("Copying stored comment (not packed)\n"); |
... | ... |
@@ -1482,17 +1512,35 @@ rar_metadata_t *cli_unrar(int fd, const char *dirname, const struct cl_limits *l |
1482 | 1482 |
init_filters(unpack_data); |
1483 | 1483 |
unpack_free_data(unpack_data); |
1484 | 1484 |
free(unpack_data); |
1485 |
- return metadata; |
|
1485 |
+ free(state->comment_dir); |
|
1486 |
+ return CL_EFORMAT; /* truncated? */ |
|
1486 | 1487 |
} |
1487 | 1488 |
} |
1488 |
- for (;;) { |
|
1489 |
- file_header=read_block(fd, FILE_HEAD); |
|
1489 |
+ |
|
1490 |
+ state->unpack_data = unpack_data; |
|
1491 |
+ state->main_hdr = main_hdr; |
|
1492 |
+ state->metadata_tail = state->metadata = NULL; |
|
1493 |
+ state->file_count = 1; |
|
1494 |
+ state->offset = offset; |
|
1495 |
+ state->fd = fd; |
|
1496 |
+ |
|
1497 |
+ return CL_SUCCESS; |
|
1498 |
+} |
|
1499 |
+ |
|
1500 |
+int cli_unrar_extract_next(rar_state_t* state,const char* dirname) |
|
1501 |
+{ |
|
1502 |
+ int retval; |
|
1503 |
+ unsigned char filename[1024]; |
|
1504 |
+ int ofd; |
|
1505 |
+ |
|
1506 |
+ rar_metadata_t *new_metadata; |
|
1507 |
+ file_header_t *file_header = read_block(state->fd, FILE_HEAD); |
|
1490 | 1508 |
if (!file_header) { |
1491 |
- break; |
|
1509 |
+ return CL_BREAK;/* end of archive */ |
|
1492 | 1510 |
} |
1493 | 1511 |
new_metadata = cli_malloc(sizeof(rar_metadata_t)); |
1494 | 1512 |
if (!new_metadata) { |
1495 |
- break; |
|
1513 |
+ return CL_EMEM; |
|
1496 | 1514 |
} |
1497 | 1515 |
new_metadata->pack_size = file_header->pack_size; |
1498 | 1516 |
new_metadata->unpack_size = file_header->unpack_size; |
... | ... |
@@ -1501,32 +1549,17 @@ rar_metadata_t *cli_unrar(int fd, const char *dirname, const struct cl_limits *l |
1501 | 1501 |
new_metadata->filename = strdup(file_header->filename); |
1502 | 1502 |
new_metadata->next = NULL; |
1503 | 1503 |
new_metadata->encrypted = FALSE; |
1504 |
- if (metadata_tail == NULL) { |
|
1505 |
- metadata_tail = metadata = new_metadata; |
|
1504 |
+ if (state->metadata_tail == NULL) { |
|
1505 |
+ state->metadata_tail = state->metadata = new_metadata; |
|
1506 | 1506 |
} else { |
1507 |
- metadata_tail->next = new_metadata; |
|
1508 |
- metadata_tail = new_metadata; |
|
1509 |
- } |
|
1510 |
- if (limits) { |
|
1511 |
- if (limits->maxratio && file_header->unpack_size && file_header->pack_size) { |
|
1512 |
- if(file_header->unpack_size / file_header->pack_size >= limits->maxratio) { |
|
1513 |
- free(file_header->filename); |
|
1514 |
- free(file_header); |
|
1515 |
- break; |
|
1516 |
- } |
|
1517 |
- } |
|
1518 |
- |
|
1519 |
- if (limits->maxfilesize && (file_header->unpack_size > (unsigned int) limits->maxfilesize)) { |
|
1520 |
- free(file_header->filename); |
|
1521 |
- free(file_header); |
|
1522 |
- break; |
|
1523 |
- } |
|
1507 |
+ state->metadata_tail->next = new_metadata; |
|
1508 |
+ state->metadata_tail = new_metadata; |
|
1524 | 1509 |
} |
1525 | 1510 |
if (file_header->flags & LHD_COMMENT) { |
1526 | 1511 |
comment_header_t *comment_header; |
1527 | 1512 |
|
1528 | 1513 |
cli_dbgmsg("File comment present\n"); |
1529 |
- comment_header = read_header(fd, COMM_HEAD); |
|
1514 |
+ comment_header = read_header(state->fd, COMM_HEAD); |
|
1530 | 1515 |
if (comment_header) { |
1531 | 1516 |
cli_dbgmsg("Comment type: 0x%.2x\n", comment_header->head_type); |
1532 | 1517 |
cli_dbgmsg("Head size: 0x%.4x\n", comment_header->head_size); |
... | ... |
@@ -1538,63 +1571,62 @@ rar_metadata_t *cli_unrar(int fd, const char *dirname, const struct cl_limits *l |
1538 | 1538 |
(comment_header->method > 0x30)) { |
1539 | 1539 |
cli_dbgmsg("Can't process file comment - skipping\n"); |
1540 | 1540 |
} else { |
1541 |
- snprintf(filename, 1024, "%s/%lu.cmt", dirname, file_count); |
|
1541 |
+ snprintf(filename, 1024, "%s/%lu.cmt", state->comment_dir, state->file_count); |
|
1542 | 1542 |
ofd = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0600); |
1543 | 1543 |
if (ofd < 0) { |
1544 | 1544 |
free(comment_header); |
1545 | 1545 |
cli_dbgmsg("ERROR: Failed to open output file\n"); |
1546 | 1546 |
} else { |
1547 | 1547 |
cli_dbgmsg("Copying file comment (not packed)\n"); |
1548 |
- copy_file_data(fd, ofd, comment_header->unpack_size); |
|
1548 |
+ copy_file_data(state->fd, ofd, comment_header->unpack_size); |
|
1549 | 1549 |
close(ofd); |
1550 | 1550 |
} |
1551 | 1551 |
} |
1552 | 1552 |
free(comment_header); |
1553 | 1553 |
} |
1554 | 1554 |
} |
1555 |
- if (lseek(fd, file_header->start_offset+file_header->head_size, SEEK_SET) != |
|
1555 |
+ if (lseek(state->fd, file_header->start_offset+file_header->head_size, SEEK_SET) != |
|
1556 | 1556 |
file_header->start_offset+file_header->head_size) { |
1557 |
- cli_dbgmsg("Seek failed: %ld\n", offset+file_header->head_size); |
|
1557 |
+ cli_dbgmsg("Seek failed: %ld\n", state->offset+file_header->head_size); |
|
1558 | 1558 |
free(file_header->filename); |
1559 | 1559 |
free(file_header); |
1560 |
- break; |
|
1560 |
+ return CL_ERAR; |
|
1561 | 1561 |
} |
1562 | 1562 |
if (file_header->flags & LHD_PASSWORD) { |
1563 | 1563 |
cli_dbgmsg("PASSWORDed file: %s\n", file_header->filename); |
1564 |
- metadata_tail->encrypted = TRUE; |
|
1564 |
+ state->metadata_tail->encrypted = TRUE; |
|
1565 | 1565 |
} else /*if (file_header->unpack_size)*/ { |
1566 |
- snprintf(filename, 1024, "%s/%lu.ura", dirname, file_count); |
|
1567 |
- ofd = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0600); |
|
1566 |
+ snprintf(state->filename, 1024, "%s/%lu.ura", dirname, state->file_count); |
|
1567 |
+ ofd = open(state->filename, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0600); |
|
1568 | 1568 |
if (ofd < 0) { |
1569 | 1569 |
free(file_header->filename); |
1570 | 1570 |
free(file_header); |
1571 | 1571 |
cli_dbgmsg("ERROR: Failed to open output file\n"); |
1572 |
- continue; |
|
1572 |
+ return CL_EOPEN; |
|
1573 | 1573 |
} |
1574 |
- unpack_data->ofd = ofd; |
|
1574 |
+ state->unpack_data->ofd = ofd; |
|
1575 | 1575 |
if (file_header->method == 0x30) { |
1576 | 1576 |
cli_dbgmsg("Copying stored file (not packed)\n"); |
1577 |
- copy_file_data(fd, ofd, file_header->pack_size); |
|
1577 |
+ copy_file_data(state->fd, ofd, file_header->pack_size); |
|
1578 | 1578 |
} else { |
1579 |
- unpack_data->dest_unp_size = file_header->unpack_size; |
|
1580 |
- unpack_data->pack_size = file_header->pack_size; |
|
1579 |
+ state->unpack_data->dest_unp_size = file_header->unpack_size; |
|
1580 |
+ state->unpack_data->pack_size = file_header->pack_size; |
|
1581 | 1581 |
if (file_header->unpack_ver <= 15) { |
1582 |
- retval = rar_unpack(fd, 15, (file_count>1) && |
|
1583 |
- ((main_hdr->flags&MHD_SOLID)!=0), unpack_data); |
|
1582 |
+ retval = rar_unpack(state->fd, 15, (state->file_count>1) && |
|
1583 |
+ ((state->main_hdr->flags&MHD_SOLID)!=0), state->unpack_data); |
|
1584 | 1584 |
} else { |
1585 |
- if ((file_count == 1) && (file_header->flags & LHD_SOLID)) { |
|
1585 |
+ if ((state->file_count == 1) && (file_header->flags & LHD_SOLID)) { |
|
1586 | 1586 |
cli_warnmsg("RAR: First file can't be SOLID.\n"); |
1587 |
- close(ofd); |
|
1588 |
- break; |
|
1587 |
+ return CL_ERAR; |
|
1589 | 1588 |
} else { |
1590 |
- retval = rar_unpack(fd, file_header->unpack_ver, |
|
1591 |
- file_header->flags & LHD_SOLID, unpack_data); |
|
1589 |
+ retval = rar_unpack(state->fd, file_header->unpack_ver, |
|
1590 |
+ file_header->flags & LHD_SOLID, state->unpack_data); |
|
1592 | 1591 |
} |
1593 | 1592 |
} |
1594 | 1593 |
cli_dbgmsg("Expected File CRC: 0x%x\n", file_header->file_crc); |
1595 |
- cli_dbgmsg("Computed File CRC: 0x%x\n", unpack_data->unp_crc^0xffffffff); |
|
1596 |
- if (unpack_data->unp_crc != 0xffffffff) { |
|
1597 |
- if (file_header->file_crc != (unpack_data->unp_crc^0xffffffff)) { |
|
1594 |
+ cli_dbgmsg("Computed File CRC: 0x%x\n", state->unpack_data->unp_crc^0xffffffff); |
|
1595 |
+ if (state->unpack_data->unp_crc != 0xffffffff) { |
|
1596 |
+ if (file_header->file_crc != (state->unpack_data->unp_crc^0xffffffff)) { |
|
1598 | 1597 |
cli_warnmsg("RAR CRC error. Please report the bug at http://bugs.clamav.net/\n"); |
1599 | 1598 |
} |
1600 | 1599 |
} |
... | ... |
@@ -1602,34 +1634,31 @@ rar_metadata_t *cli_unrar(int fd, const char *dirname, const struct cl_limits *l |
1602 | 1602 |
cli_dbgmsg("Corrupt file detected\n"); |
1603 | 1603 |
if (file_header->flags & LHD_SOLID) { |
1604 | 1604 |
cli_dbgmsg("SOLID archive, can't continue\n"); |
1605 |
- close(ofd); |
|
1606 |
- break; |
|
1605 |
+ return CL_ERAR; |
|
1607 | 1606 |
} |
1608 | 1607 |
} |
1609 | 1608 |
} |
1610 | 1609 |
|
1611 |
- close(ofd); |
|
1612 | 1610 |
} |
1613 |
- if (lseek(fd, file_header->next_offset, SEEK_SET) != file_header->next_offset) { |
|
1611 |
+ if (lseek(state->fd, file_header->next_offset, SEEK_SET) != file_header->next_offset) { |
|
1614 | 1612 |
cli_dbgmsg("ERROR: seek failed: %ld\n", file_header->next_offset); |
1615 | 1613 |
free(file_header->filename); |
1616 | 1614 |
free(file_header); |
1617 |
- free(main_hdr); |
|
1618 |
- ppm_destructor(&unpack_data->ppm_data); |
|
1619 |
- init_filters(unpack_data); |
|
1620 |
- unpack_free_data(unpack_data); |
|
1621 |
- free(unpack_data); |
|
1622 |
- return metadata; |
|
1615 |
+ return CL_ERAR; |
|
1623 | 1616 |
} |
1624 | 1617 |
free(file_header->filename); |
1625 | 1618 |
free(file_header); |
1626 |
- unpack_free_data(unpack_data); |
|
1627 |
- file_count++; |
|
1628 |
- } |
|
1629 |
- ppm_destructor(&unpack_data->ppm_data); |
|
1630 |
- free(main_hdr); |
|
1631 |
- init_filters(unpack_data); |
|
1632 |
- unpack_free_data(unpack_data); |
|
1633 |
- free(unpack_data); |
|
1634 |
- return metadata; |
|
1619 |
+ unpack_free_data(state->unpack_data); |
|
1620 |
+ state->file_count++; |
|
1621 |
+ return CL_SUCCESS; |
|
1622 |
+ } |
|
1623 |
+ |
|
1624 |
+void cli_unrar_close(rar_state_t* state) |
|
1625 |
+{ |
|
1626 |
+ ppm_destructor(&state->unpack_data->ppm_data); |
|
1627 |
+ free(state->main_hdr); |
|
1628 |
+ init_filters(state->unpack_data); |
|
1629 |
+ unpack_free_data(state->unpack_data); |
|
1630 |
+ free(state->unpack_data); |
|
1631 |
+ free(state->comment_dir); |
|
1635 | 1632 |
} |
... | ... |
@@ -56,6 +56,7 @@ typedef struct rar_metadata_tag |
56 | 56 |
struct rar_metadata_tag *next; |
57 | 57 |
} rar_metadata_t; |
58 | 58 |
|
59 |
+ |
|
59 | 60 |
#define SIZEOF_MARKHEAD 7 |
60 | 61 |
#define SIZEOF_NEWMHD 13 |
61 | 62 |
#define SIZEOF_NEWLHD 32 |
... | ... |
@@ -291,6 +292,18 @@ typedef struct unpack_data_tag |
291 | 291 |
unsigned int ntopl[256], ntoplb[256], ntoplc[256]; |
292 | 292 |
} unpack_data_t; |
293 | 293 |
|
294 |
+typedef struct rar_state_tag { |
|
295 |
+ rar_metadata_t *metadata; |
|
296 |
+ rar_metadata_t *metadata_tail; |
|
297 |
+ unpack_data_t *unpack_data; |
|
298 |
+ main_header_t *main_hdr; |
|
299 |
+ const char* comment_dir; |
|
300 |
+ unsigned long file_count; |
|
301 |
+ off_t offset; |
|
302 |
+ int fd; |
|
303 |
+ char filename[1024]; |
|
304 |
+} rar_state_t; |
|
305 |
+ |
|
294 | 306 |
typedef enum |
295 | 307 |
{ |
296 | 308 |
ALL_HEAD=0, |
... | ... |
@@ -312,7 +325,10 @@ enum BLOCK_TYPES |
312 | 312 |
BLOCK_PPM |
313 | 313 |
}; |
314 | 314 |
|
315 |
-rar_metadata_t *cli_unrar(int fd, const char *dirname, const struct cl_limits *limits); |
|
315 |
+ |
|
316 |
+int cli_unrar_extract_next(rar_state_t* state,const char* dirname); |
|
317 |
+int cli_unrar_open(int fd, const char *dirname, rar_state_t* state); |
|
318 |
+void cli_unrar_close(rar_state_t* state); |
|
316 | 319 |
unsigned int rar_get_char(int fd, unpack_data_t *unpack_data); |
317 | 320 |
void addbits(unpack_data_t *unpack_data, int bits); |
318 | 321 |
unsigned int getbits(unpack_data_t *unpack_data); |