int cli_scannulsft(cli_ctx *ctx, off_t offset) { int ret; struct nsis_st nsist; cli_dbgmsg("in scannulsft()\n"); memset(&nsist, 0, sizeof(struct nsis_st)); nsist.off = offset; if (!(nsist.dir = cli_gentemp(ctx->engine->tmpdir))) return CL_ETMPDIR; if(mkdir(nsist.dir, 0700)) { cli_dbgmsg("NSIS: Can't create temporary directory %s\n", nsist.dir); free(nsist.dir); return CL_ETMPDIR; } nsist.map = *ctx->fmap; if(ctx->engine->keeptmp) cli_dbgmsg("NSIS: Extracting files to %s\n", nsist.dir); do { ret = cli_nsis_unpack(&nsist, ctx); if (ret == CL_SUCCESS && nsist.opened == 0) { /* Don't scan a non-existent file */ continue; } if (ret == CL_SUCCESS) { cli_dbgmsg("NSIS: Successully extracted file #%u\n", nsist.fno); if (lseek(nsist.ofd, 0, SEEK_SET) == -1) { cli_dbgmsg("NSIS: call to lseek() failed\n"); free(nsist.dir); return CL_ESEEK; } if(nsist.fno == 1) ret=cli_scandesc(nsist.ofd, ctx, 0, 0, NULL, AC_SCAN_VIR, NULL); else ret=cli_magic_scandesc(nsist.ofd, ctx); close(nsist.ofd); if(!ctx->engine->keeptmp) if(cli_unlink(nsist.ofn)) ret = CL_EUNLINK; } else if(ret == CL_EMAXSIZE) { ret = nsist.solid ? CL_BREAK : CL_SUCCESS; } } while(ret == CL_SUCCESS); if(ret == CL_BREAK || ret == CL_EMAXFILES) ret = CL_CLEAN; nsis_shutdown(&nsist); if(!ctx->engine->keeptmp) cli_rmdirs(nsist.dir); free(nsist.dir); return ret; }
static void cli_nsis_free(struct nsis_st *n) { nsis_shutdown(n); if (n->solid && n->freeme) free(n->freeme); }
static int nsis_unpack_next(struct nsis_st *n, cli_ctx *ctx) { unsigned char *ibuf; uint32_t size, loops; int ret; unsigned char obuf[BUFSIZ]; if (n->eof) { cli_dbgmsg("NSIS: extraction complete\n"); return CL_BREAK; } if (ctx->limits && ctx->limits->maxfiles && n->fno >= ctx->limits->maxfiles) { cli_dbgmsg("NSIS: Files limit reached (max: %u)\n", ctx->limits->maxfiles); return CL_EMAXFILES; } if (n->fno) snprintf(n->ofn, 1023, "%s/content.%.3u", n->dir, n->fno); else snprintf(n->ofn, 1023, "%s/headers", n->dir); n->fno++; if ((n->ofd=open(n->ofn, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0600))==-1) { cli_errmsg("NSIS: unable to create output file %s - aborting.", n->ofn); return CL_EIO; } if (!n->solid) { if (cli_readn(n->ifd, &size, 4)!=4) { cli_dbgmsg("NSIS: reached EOF - extraction complete\n"); close(n->ofd); return CL_BREAK; } if (n->asz==4) { cli_dbgmsg("NSIS: reached CRC - extraction complete\n"); close(n->ofd); return CL_BREAK; } loops = EC32(size); if (!(size = (loops&~0x80000000))) { cli_dbgmsg("NSIS: empty file found\n"); return CL_SUCCESS; } if (n->asz <4 || size > n->asz-4) { cli_dbgmsg("NSIS: next file is outside the archive\n"); close(n->ofd); return CL_BREAK; } n->asz -= size+4; if (ctx->limits && ctx->limits->maxfilesize && size > ctx->limits->maxfilesize) { cli_dbgmsg("NSIS: Skipping file due to size limit (%u, max: %lu)\n", size, ctx->limits->maxfilesize); close(n->ofd); if (lseek(n->ifd, size, SEEK_CUR)==-1) return CL_EIO; return CL_EMAXSIZE; } if (!(ibuf= (unsigned char *) cli_malloc(size))) { cli_dbgmsg("NSIS: out of memory"__AT__"\n"); close(n->ofd); return CL_EMEM; } if (cli_readn(n->ifd, ibuf, size) != (ssize_t) size) { cli_dbgmsg("NSIS: cannot read %u bytes"__AT__"\n", size); free(ibuf); close(n->ofd); return CL_EIO; } if (loops==size) { if (cli_writen(n->ofd, ibuf, size) != (ssize_t) size) { cli_dbgmsg("NSIS: cannot write output file"__AT__"\n"); free(ibuf); close(n->ofd); return CL_EIO; } } else { if ((ret=nsis_init(n))!=CL_SUCCESS) { cli_dbgmsg("NSIS: decompressor init failed"__AT__"\n"); free(ibuf); close(n->ofd); return ret; } n->nsis.avail_in = size; n->nsis.next_in = ibuf; n->nsis.next_out = obuf; n->nsis.avail_out = BUFSIZ; loops=0; while ((ret=nsis_decomp(n))==CL_SUCCESS) { if ((size = n->nsis.next_out - obuf)) { if (cli_writen(n->ofd, obuf, size) != (ssize_t) size) { cli_dbgmsg("NSIS: cannot write output file"__AT__"\n"); free(ibuf); close(n->ofd); return CL_EIO; } n->nsis.next_out = obuf; n->nsis.avail_out = BUFSIZ; loops=0; if (ctx->limits && ctx->limits->maxfilesize && size > ctx->limits->maxfilesize) { cli_dbgmsg("NSIS: Skipping file due to size limit (%u, max: %lu)\n", size, ctx->limits->maxfilesize); free(ibuf); close(n->ofd); nsis_shutdown(n); return CL_EMAXSIZE; } } else if (++loops > 10) { cli_dbgmsg("NSIS: xs looping, breaking out"__AT__"\n"); ret = CL_BREAK; break; } } if (ret != CL_BREAK) { cli_dbgmsg("NSIS: bad stream"__AT__"\n"); free(ibuf); close(n->ofd); return CL_EFORMAT; } if (cli_writen(n->ofd, obuf, n->nsis.next_out - obuf) != n->nsis.next_out - obuf) { cli_dbgmsg("NSIS: cannot write output file"__AT__"\n"); free(ibuf); close(n->ofd); return CL_EIO; } nsis_shutdown(n); } free(ibuf); return CL_SUCCESS; } else { if (!n->freeme) { if ((ret=nsis_init(n))!=CL_SUCCESS) { cli_dbgmsg("NSIS: decompressor init failed\n"); close(n->ofd); return ret; } if (!(n->freeme= (unsigned char *) cli_malloc(n->asz))) { cli_dbgmsg("NSIS: out of memory\n"); close(n->ofd); return CL_EMEM; } if (cli_readn(n->ifd, n->freeme, n->asz) != (ssize_t) n->asz) { cli_dbgmsg("NSIS: cannot read %u bytes"__AT__"\n", n->asz); close(n->ofd); return CL_EIO; } n->nsis.next_in = n->freeme; n->nsis.avail_in = n->asz; } if (n->nsis.avail_in<=4) { cli_dbgmsg("NSIS: extraction complete\n"); close(n->ofd); return CL_BREAK; } n->nsis.next_out = obuf; n->nsis.avail_out = 4; loops = 0; while ((ret=nsis_decomp(n))==CL_SUCCESS) { if (n->nsis.next_out - obuf == 4) break; if (++loops > 20) { cli_dbgmsg("NSIS: xs looping, breaking out"__AT__"\n"); ret = CL_BREAK; break; } } if (ret != CL_SUCCESS) { cli_dbgmsg("NSIS: bad stream"__AT__"\n"); close(n->ofd); return CL_EFORMAT; } size=cli_readint32(obuf); if (ctx->limits && ctx->limits->maxfilesize && size > ctx->limits->maxfilesize) { cli_dbgmsg("NSIS: Breaking out due to filesize limit (%u, max: %lu) in solid archive\n", size, ctx->limits->maxfilesize); close(n->ofd); return CL_EFORMAT; } n->nsis.next_out = obuf; n->nsis.avail_out = MIN(BUFSIZ,size); loops = 0; while (size && (ret=nsis_decomp(n))==CL_SUCCESS) { unsigned int wsz; if ((wsz = n->nsis.next_out - obuf)) { if (cli_writen(n->ofd, obuf, wsz) != (ssize_t) wsz) { close(n->ofd); return CL_EIO; } size-=wsz; n->nsis.next_out = obuf; n->nsis.avail_out = MIN(size,BUFSIZ); } else if ( ++loops > 20 ) { cli_dbgmsg("NSIS: xs looping, breaking out"__AT__"\n"); ret = CL_BREAK; break; } } if (ret == CL_BREAK) { if (cli_writen(n->ofd, obuf, n->nsis.next_out - obuf) != n->nsis.next_out - obuf) { close(n->ofd); return CL_EIO; } n->eof=1; } else if (ret != CL_SUCCESS) { cli_dbgmsg("NSIS: bad stream"__AT__"\n"); close(n->ofd); return CL_EFORMAT; } return CL_SUCCESS; } }
static int nsis_unpack_next(struct nsis_st *n, cli_ctx *ctx) { const unsigned char *ibuf; uint32_t size, loops; int ret, gotsome=0, opened=0; unsigned char obuf[BUFSIZ]; if (n->eof) { cli_dbgmsg("NSIS: extraction complete\n"); return CL_BREAK; } if ((ret=cli_checklimits("NSIS", ctx, 0, 0, 0))!=CL_CLEAN) return ret; if (n->fno) snprintf(n->ofn, 1023, "%s"PATHSEP"content.%.3u", n->dir, n->fno); else snprintf(n->ofn, 1023, "%s"PATHSEP"headers", n->dir); n->fno++; n->opened = 0; if (!n->solid) { if (fmap_readn(n->map, &size, n->curpos, 4)!=4) { cli_dbgmsg("NSIS: reached EOF - extraction complete\n"); return CL_BREAK; } n->curpos += 4; if (n->asz==4) { cli_dbgmsg("NSIS: reached CRC - extraction complete\n"); return CL_BREAK; } loops = EC32(size); if (!(size = (loops&~0x80000000))) { cli_dbgmsg("NSIS: empty file found\n"); return CL_SUCCESS; } if (n->asz <4 || size > n->asz-4) { cli_dbgmsg("NSIS: next file is outside the archive\n"); return CL_BREAK; } n->asz -= size+4; if ((ret=cli_checklimits("NSIS", ctx, size, 0, 0))!=CL_CLEAN) { n->curpos += size; return ret; } if (!(ibuf = fmap_need_off_once(n->map, n->curpos, size))) { cli_dbgmsg("NSIS: cannot read %u bytes"__AT__"\n", size); return CL_EREAD; } if ((n->ofd=open(n->ofn, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0600))==-1) { cli_errmsg("NSIS: unable to create output file %s - aborting.", n->ofn); return CL_ECREAT; } n->opened = 1; n->curpos += size; if (loops==size) { if (cli_writen(n->ofd, ibuf, size) != (ssize_t) size) { cli_dbgmsg("NSIS: cannot write output file"__AT__"\n"); close(n->ofd); return CL_EWRITE; } } else { if ((ret=nsis_init(n))!=CL_SUCCESS) { cli_dbgmsg("NSIS: decompressor init failed"__AT__"\n"); close(n->ofd); return ret; } n->nsis.avail_in = size; n->nsis.next_in = (void*)ibuf; n->nsis.next_out = obuf; n->nsis.avail_out = BUFSIZ; loops=0; while ((ret=nsis_decomp(n))==CL_SUCCESS) { if ((size = n->nsis.next_out - obuf)) { gotsome=1; if (cli_writen(n->ofd, obuf, size) != (ssize_t) size) { cli_dbgmsg("NSIS: cannot write output file"__AT__"\n"); close(n->ofd); nsis_shutdown(n); return CL_EWRITE; } n->nsis.next_out = obuf; n->nsis.avail_out = BUFSIZ; loops=0; if ((ret=cli_checklimits("NSIS", ctx, size, 0, 0))!=CL_CLEAN) { close(n->ofd); nsis_shutdown(n); return ret; } } else if (++loops > 20) { cli_dbgmsg("NSIS: xs looping, breaking out"__AT__"\n"); ret = CL_EFORMAT; break; } } nsis_shutdown(n); if (n->nsis.next_out - obuf) { gotsome=1; if (cli_writen(n->ofd, obuf, n->nsis.next_out - obuf) != n->nsis.next_out - obuf) { cli_dbgmsg("NSIS: cannot write output file"__AT__"\n"); close(n->ofd); return CL_EWRITE; } } if (ret != CL_SUCCESS && ret != CL_BREAK) { cli_dbgmsg("NSIS: bad stream"__AT__"\n"); if (gotsome) { ret = CL_SUCCESS; } else { ret = CL_EMAXSIZE; close(n->ofd); } return ret; } } return CL_SUCCESS; } else { if (!n->freeme) { if ((ret=nsis_init(n))!=CL_SUCCESS) { cli_dbgmsg("NSIS: decompressor init failed\n"); return ret; } if(!(n->freeme = fmap_need_off_once(n->map, n->curpos, n->asz))) { cli_dbgmsg("NSIS: cannot read %u bytes"__AT__"\n", n->asz); return CL_EREAD; } n->nsis.next_in = (void*)n->freeme; n->nsis.avail_in = n->asz; } if (n->nsis.avail_in<=4) { cli_dbgmsg("NSIS: extraction complete\n"); return CL_BREAK; } n->nsis.next_out = obuf; n->nsis.avail_out = 4; loops = 0; while ((ret=nsis_decomp(n))==CL_SUCCESS) { if (n->nsis.next_out - obuf == 4) break; if (++loops > 20) { cli_dbgmsg("NSIS: xs looping, breaking out"__AT__"\n"); ret = CL_BREAK; break; } } if (ret != CL_SUCCESS) { cli_dbgmsg("NSIS: bad stream"__AT__"\n"); return CL_EFORMAT; } size=cli_readint32(obuf); if ((ret=cli_checklimits("NSIS", ctx, size, 0, 0))!=CL_CLEAN) { return ret; } if (size == 0) { cli_dbgmsg("NSIS: Empty file found.\n"); return CL_SUCCESS; } n->nsis.next_out = obuf; n->nsis.avail_out = MIN(BUFSIZ,size); loops = 0; if ((n->ofd=open(n->ofn, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0600))==-1) { cli_errmsg("NSIS: unable to create output file %s - aborting.", n->ofn); return CL_ECREAT; } n->opened = 1; while (size && (ret=nsis_decomp(n))==CL_SUCCESS) { unsigned int wsz; if ((wsz = n->nsis.next_out - obuf)) { gotsome=1; if (cli_writen(n->ofd, obuf, wsz) != (ssize_t) wsz) { cli_dbgmsg("NSIS: cannot write output file"__AT__"\n"); close(n->ofd); return CL_EWRITE; } size-=wsz; loops=0; n->nsis.next_out = obuf; n->nsis.avail_out = MIN(size,BUFSIZ); } else if ( ++loops > 20 ) { cli_dbgmsg("NSIS: xs looping, breaking out"__AT__"\n"); ret = CL_EFORMAT; break; } } if (n->nsis.next_out - obuf) { gotsome=1; if (cli_writen(n->ofd, obuf, n->nsis.next_out - obuf) != n->nsis.next_out - obuf) { cli_dbgmsg("NSIS: cannot write output file"__AT__"\n"); close(n->ofd); return CL_EWRITE; } } if (ret == CL_EFORMAT) { cli_dbgmsg("NSIS: bad stream"__AT__"\n"); if (!gotsome) { close(n->ofd); return CL_EMAXSIZE; } } if (ret == CL_EFORMAT || ret == CL_BREAK) { n->eof=1; } else if (ret != CL_SUCCESS) { cli_dbgmsg("NSIS: bad stream"__AT__"\n"); close(n->ofd); return CL_EFORMAT; } return CL_SUCCESS; } }