Exemple #1
0
int nc_connect_rand(int *main, int *alt, int *local) {
    struct CP_ENTRY *cpe = cpool_get_rand(main);

    if(!cpe) return 1;
    *local = (cpe->server->sa_family == AF_UNIX);
    if(*local) {
	char *unlinkme;
	if(cli_gentempfd(tempdir, &unlinkme, alt) != CL_SUCCESS) {
	    logg("!Failed to create temporary file\n");
	    close(*main);
	    return 1;
	}
	unlink(unlinkme);
	free(unlinkme);
	if(nc_send(*main, "nFILDES\n", 8)) {
	    logg("!FD scan request failed\n");
	    close(*alt);
	    close(*main);
	    return 1;
	}
    } else {
	if(nc_send(*main, "nINSTREAM\n", 10)) {
	    logg("!Failed to communicate with clamd\n");
	    close(*main);
	    return 1;
	}
    }
    return 0;
}
Exemple #2
0
static char *dump_xdp(cli_ctx *ctx, const char *start, size_t sz)
{
    int fd;
    char *filename;
    size_t nwritten=0;
    ssize_t writeret;

    if (cli_gentempfd(ctx->engine->tmpdir, &filename, &fd) != CL_SUCCESS)
        return NULL;

    while (nwritten < sz) {
        writeret = write(fd, start+nwritten, sz-nwritten);
        if (writeret < 0) {
            if (errno == EAGAIN)
                continue;

            close(fd);
            cli_unlink(filename);
            free(filename);

            return NULL;
        }

        nwritten += writeret;
    }

    cli_dbgmsg("dump_xdp: Dumped payload to %s\n", filename);

    close(fd);

    return filename;
}
Exemple #3
0
/*
  xar_process_subdocument - check TOC for xml subdocument. If found, extract and
                            scan in memory.
  Parameters:
     reader - xmlTextReaderPtr
     ctx - pointer to cli_ctx
  Returns:
     CL_SUCCESS - subdoc found and clean scan (or virus found and SCAN_ALL), or no subdocument
     other - error return code from cli_mem_scandesc()
*/
static int xar_scan_subdocuments(xmlTextReaderPtr reader, cli_ctx *ctx)
{
    int rc = CL_SUCCESS, subdoc_len, fd;
    xmlChar * subdoc;
    const xmlChar *name;
    char * tmpname;

    while (xmlTextReaderRead(reader) == 1) {
        name = xmlTextReaderConstLocalName(reader);
        if (name == NULL) {
            cli_dbgmsg("cli_scanxar: xmlTextReaderConstLocalName() no name.\n");
            rc = CL_EFORMAT;
            break;
        }
        if (xmlStrEqual(name, (const xmlChar *)"toc") &&
                xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT)
            return CL_SUCCESS;
        if (xmlStrEqual(name, (const xmlChar *)"subdoc") &&
                xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT) {
            subdoc = xmlTextReaderReadInnerXml(reader);
            if (subdoc == NULL) {
                cli_dbgmsg("cli_scanxar: no content in subdoc element.\n");
                xmlTextReaderNext(reader);
                continue;
            }
            subdoc_len = xmlStrlen(subdoc);
            cli_dbgmsg("cli_scanxar: in-memory scan of xml subdocument, len %i.\n", subdoc_len);
            rc = cli_mem_scandesc(subdoc, subdoc_len, ctx);
            if (rc == CL_VIRUS && SCAN_ALL)
                rc = CL_SUCCESS;

            /* make a file to leave if --leave-temps in effect */
            if(ctx->engine->keeptmp) {
                if ((rc = cli_gentempfd(ctx->engine->tmpdir, &tmpname, &fd)) != CL_SUCCESS) {
                    cli_dbgmsg("cli_scanxar: Can't create temporary file for subdocument.\n");
                } else {
                    cli_dbgmsg("cli_scanxar: Writing subdoc to temp file %s.\n", tmpname);
                    if (cli_writen(fd, subdoc, subdoc_len) < 0) {
                        cli_dbgmsg("cli_scanxar: cli_writen error writing subdoc temporary file.\n");
                        rc = CL_EWRITE;
                    }
                    rc = xar_cleanup_temp_file(ctx, fd, tmpname);
                }
            }

            xmlFree(subdoc);
            if (rc != CL_SUCCESS)
                return rc;
            xmlTextReaderNext(reader);
        }
    }
    return rc;
}
Exemple #4
0
void
fileblobSetFilename(fileblob *fb, const char *dir, const char *filename)
{
    char *fullname;

    if(fb->b.name)
        return;

    assert(filename != NULL);
    assert(dir != NULL);

    blobSetFilename(&fb->b, dir, filename);

    /*
     * Reload the filename, it may be different from the one we've
     * asked for, e.g. '/'s taken out
     */
    filename = blobGetFilename(&fb->b);

    assert(filename != NULL);

    if (cli_gentempfd(dir, &fullname, &fb->fd)!=CL_SUCCESS) return;

    cli_dbgmsg("fileblobSetFilename: file %s saved to %s\n", filename, fullname);

    fb->fp = fdopen(fb->fd, "wb");

    if(fb->fp == NULL) {
        cli_errmsg("fileblobSetFilename: fdopen failed\n");
        close(fb->fd);
        free(fullname);
        return;
    }
    if(fb->b.data)
        if(fileblobAddData(fb, fb->b.data, fb->b.len) == 0) {
            free(fb->b.data);
            fb->b.data = NULL;
            fb->b.len = fb->b.size = 0;
            fb->isNotEmpty = 1;
        }
    fb->fullname = fullname;
}
Exemple #5
0
int fmap_dump_to_file(fmap_t *map, const char *tmpdir, char **outname, int *outfd)
{
    char *tmpname;
    int tmpfd, ret;
    size_t pos = 0, len;

    cli_dbgmsg("fmap_dump_to_file: dumping fmap not backed by file...\n");
    ret = cli_gentempfd(tmpdir, &tmpname, &tmpfd);
    if(ret != CL_SUCCESS) {
        cli_dbgmsg("fmap_dump_to_file: failed to generate temporary file.\n");
        return ret;
    }

    do {
        const char *b;
        len = 0;
        b = fmap_need_off_once_len(map, pos, BUFSIZ, &len);
        pos += len;
        if(b && (len > 0)) {
            if ((size_t)cli_writen(tmpfd, b, len) != len) {
                cli_warnmsg("fmap_dump_to_file: write failed to %s!\n", tmpname);
                close(tmpfd);
                unlink(tmpname);
                free(tmpname);
                return CL_EWRITE;
            }
        }
    } while (len > 0);

    if(lseek(tmpfd, 0, SEEK_SET) == -1) {
        cli_dbgmsg("fmap_dump_to_file: lseek failed\n");
    }

    *outname = tmpname;
    *outfd = tmpfd;
    return CL_SUCCESS;
}
Exemple #6
0
/* returns:
 *  <0 for error
 *     -1 out of memory
 *     -2 other
 *   0 for async dispatched
 *   1 for command completed (connection can be closed)
 */
int execute_or_dispatch_command(client_conn_t *conn, enum commands cmd, const char *argument)
{
    int desc = conn->sd;
    char term = conn->term;
    const struct cl_engine *engine = conn->engine;
    /* execute commands that can be executed quickly on the recvloop thread,
     * these must:
     *  - not involve any operation that can block for a long time, such as disk
     *  I/O
     *  - send of atomic message is allowed.
     * Dispatch other commands */
    if (conn->group) {
	switch (cmd) {
	    case COMMAND_FILDES:
	    case COMMAND_SCAN:
	    case COMMAND_END:
	    case COMMAND_INSTREAM:
	    case COMMAND_INSTREAMSCAN:
	    case COMMAND_VERSION:
	    case COMMAND_PING:
	    case COMMAND_STATS:
	    case COMMAND_COMMANDS:
		/* These commands are accepted inside IDSESSION */
		break;
	    default:
		/* these commands are not recognized inside an IDSESSION */
		conn_reply_error(conn, "Command invalid inside IDSESSION.");
		logg("$SESSION: command is not valid inside IDSESSION: %d\n", cmd);
		conn->group = NULL;
		return 1;
	}
    }

    switch (cmd) {
	case COMMAND_SHUTDOWN:
	    pthread_mutex_lock(&exit_mutex);
	    progexit = 1;
	    pthread_mutex_unlock(&exit_mutex);
	    return 1;
	case COMMAND_RELOAD:
	    pthread_mutex_lock(&reload_mutex);
	    reload = 1;
	    pthread_mutex_unlock(&reload_mutex);
	    mdprintf(desc, "RELOADING%c", term);
	    /* we set reload flag, and we'll reload before closing the
	     * connection */
	    return 1;
	case COMMAND_PING:
	    if (conn->group)
		mdprintf(desc, "%u: PONG%c", conn->id, term);
	    else
		mdprintf(desc, "PONG%c", term);
	    return conn->group ? 0 : 1;
	case COMMAND_VERSION:
	    {
		if (conn->group)
		    mdprintf(desc, "%u: ", conn->id);
		print_ver(desc, conn->term, engine);
		return conn->group ? 0 : 1;
	    }
	case COMMAND_COMMANDS:
	    {
		if (conn->group)
		    mdprintf(desc, "%u: ", conn->id);
		print_commands(desc, conn->term, engine);
		return conn->group ? 0 : 1;
	    }
	case COMMAND_DETSTATSCLEAR:
	    {
		detstats_clear();
		return 1;
	    }
	case COMMAND_DETSTATS:
	    {
		detstats_print(desc, conn->term);
		return 1;
	    }
	case COMMAND_INSTREAM:
	    {
		int rc = cli_gentempfd(optget(conn->opts, "TemporaryDirectory")->strarg, &conn->filename, &conn->scanfd);
		if (rc != CL_SUCCESS)
		    return rc;
		conn->quota = optget(conn->opts, "StreamMaxLength")->numarg;
		conn->mode = MODE_STREAM;
		return 0;
	    }
	case COMMAND_STREAM:
	case COMMAND_MULTISCAN:
	case COMMAND_CONTSCAN:
	case COMMAND_STATS:
	case COMMAND_FILDES:
	case COMMAND_SCAN:
	case COMMAND_INSTREAMSCAN:
	    return dispatch_command(conn, cmd, argument);
	case COMMAND_IDSESSION:
	    conn->group = thrmgr_group_new();
	    if (!conn->group)
		return CL_EMEM;
	    return 0;
	case COMMAND_END:
	    if (!conn->group) {
		/* end without idsession? */
		conn_reply_single(conn, NULL, "UNKNOWN COMMAND");
		return 1;
	    }
	    /* need to close connection  if we were last in group */
	    return 1;
	/*case COMMAND_UNKNOWN:*/
	default:
	    conn_reply_single(conn, NULL, "UNKNOWN COMMAND");
	    return 1;
    }
}
Exemple #7
0
int cli_7unz (cli_ctx *ctx, size_t offset) {
    CFileInStream archiveStream;
    CLookToRead lookStream;
    CSzArEx db;
    SRes res;
    UInt16 utf16buf[UTFBUFSZ], *utf16name = utf16buf;
    int namelen = UTFBUFSZ, found = CL_CLEAN;
    Int64 begin_of_archive = offset;
    UInt32 viruses_found = 0;

    /* Replacement for 
       FileInStream_CreateVTable(&archiveStream); */
    archiveStream.s.Read = FileInStream_fmap_Read;
    archiveStream.s.Seek = FileInStream_fmap_Seek;
    archiveStream.s.curpos = 0;
    archiveStream.file.fmap = *ctx->fmap;

    LookToRead_CreateVTable(&lookStream, False);
  
    if(archiveStream.s.Seek(&archiveStream.s, &begin_of_archive, SZ_SEEK_SET) != 0)
	return CL_CLEAN;

    lookStream.realStream = &archiveStream.s;
    LookToRead_Init(&lookStream);

    SzArEx_Init(&db);
    res = SzArEx_Open(&db, &lookStream.s, &allocImp, &allocTempImp);
    if(res == SZ_OK) {
	UInt32 i, blockIndex = 0xFFFFFFFF;
	Byte *outBuffer = 0;
	size_t outBufferSize = 0;
	unsigned int encrypted = 0;

	for (i = 0; i < db.db.NumFiles; i++) {
	    size_t offset = 0;
	    size_t outSizeProcessed = 0;
	    const CSzFileItem *f = db.db.Files + i;
	    char *name;
	    size_t j;
	    int newnamelen, fd;

	    if((found = cli_checklimits("7unz", ctx, 0, 0, 0)))
		break;

	    if (f->IsDir)
		continue;

	    if(cli_checklimits("7unz", ctx, f->Size, 0, 0))
		continue;

	    if (!db.FileNameOffsets)
		newnamelen = 0; /* no filename */
	    else {
		newnamelen = SzArEx_GetFileNameUtf16(&db, i, NULL);
		if (newnamelen > namelen) {
		    if(namelen > UTFBUFSZ)
			free(utf16name);
		    utf16name = cli_malloc(newnamelen*2);
		    if(!utf16name) {
			found = CL_EMEM;
			break;
		    }
		    namelen = newnamelen;
		}
		SzArEx_GetFileNameUtf16(&db, i, utf16name);
	    }

	    name = (char *)utf16name;
	    for(j=0; j<(size_t)newnamelen; j++) /* FIXME */
		name[j] = utf16name[j];
	    name[j] = 0;
	    cli_dbgmsg("cli_7unz: extracting %s\n", name);

	    res = SzArEx_Extract(&db, &lookStream.s, i, &blockIndex, &outBuffer, &outBufferSize, &offset, &outSizeProcessed, &allocImp, &allocTempImp);
	    if(res == SZ_ERROR_ENCRYPTED) {
		encrypted = 1;
		if(DETECT_ENCRYPTED) {
		    cli_dbgmsg("cli_7unz: Encrypted files found in archive.\n");
		    cli_append_virus(ctx, "Heuristics.Encrypted.7Zip");
		    viruses_found++;
		    if(!SCAN_ALL) {
			found = CL_VIRUS;
			break;
		    }
		}
	    }
	    if(cli_matchmeta(ctx, name, 0, f->Size, encrypted, i, f->CrcDefined ? f->Crc : 0, NULL)) {
		found = CL_VIRUS;
		viruses_found++;
		if (!SCAN_ALL)
		    break;
	    }
	    if (res != SZ_OK)
		cli_dbgmsg("cli_unz: extraction failed with %d\n", res);
	    else {
		if((found = cli_gentempfd(ctx->engine->tmpdir, &name, &fd)))
		    break;
		    
		cli_dbgmsg("cli_7unz: Saving to %s\n", name);
		if((size_t)cli_writen(fd, outBuffer + offset, outSizeProcessed) != outSizeProcessed)
		    found = CL_EWRITE;
		else
		    if ((found = cli_magic_scandesc(fd, ctx)) == CL_VIRUS)
			viruses_found++;
		close(fd);
		if(!ctx->engine->keeptmp && cli_unlink(name))
		    found = CL_EUNLINK;

		free(name);
		if(found != CL_CLEAN)
		    if (!(SCAN_ALL && found == CL_VIRUS))
			break;
	    }
	}
	IAlloc_Free(&allocImp, outBuffer);
    }
    SzArEx_Free(&db, &allocImp);
    if(namelen > UTFBUFSZ)
	free(utf16name);

    if (res == SZ_OK)
	cli_dbgmsg("cli_7unz: completed successfully\n");
    else if (res == SZ_ERROR_UNSUPPORTED)
	cli_dbgmsg("cli_7unz: unsupported\n");
    else if (res == SZ_ERROR_MEM)
	cli_dbgmsg("cli_7unz: oom\n");
    else if (res == SZ_ERROR_CRC)
	cli_dbgmsg("cli_7unz: crc mismatch\n");
    else
	cli_dbgmsg("cli_7unz: error %d\n", res);

    if (SCAN_ALL && viruses_found)
	return CL_VIRUS;
    return found;
}
Exemple #8
0
int scanstream(int odesc, unsigned long int *scanned, const struct cl_engine *engine, unsigned int options, const struct optstruct *opts, char term)
{
	int ret, sockfd, acceptd;
	int tmpd, bread, retval, firsttimeout, timeout, btread;
	unsigned int port = 0, portscan, min_port, max_port;
	unsigned long int quota = 0, maxsize = 0;
	short bound = 0;
	const char *virname;
	char buff[FILEBUFF];
	char peer_addr[32];
	struct cb_context context;
	struct sockaddr_in server;
	struct sockaddr_in peer;
	socklen_t addrlen;
	char *tmpname;


    min_port = optget(opts, "StreamMinPort")->numarg;
    max_port = optget(opts, "StreamMaxPort")->numarg;

    /* search for a free port to bind to */
    port = cli_rndnum(max_port - min_port);
    bound = 0;
    for (portscan = 0; portscan < 1000; portscan++) {
	port = (port - 1) % (max_port - min_port + 1);

	memset((char *) &server, 0, sizeof(server));
	server.sin_family = AF_INET;
	server.sin_port = htons(min_port + port);
	server.sin_addr.s_addr = htonl(INADDR_ANY);

	if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
	    continue;

	if(bind(sockfd, (struct sockaddr *) &server, (socklen_t)sizeof(struct sockaddr_in)) == -1)
	    closesocket(sockfd);
	else {
	    bound = 1;
	    break;
	}
    }
    port += min_port;

    timeout = optget(opts, "ReadTimeout")->numarg;
    firsttimeout = optget(opts, "CommandReadTimeout")->numarg;

    if(!bound) {
	logg("!ScanStream: Can't find any free port.\n");
	mdprintf(odesc, "Can't find any free port. ERROR%c", term);
	return -1;
    } else {
	if (listen(sockfd, 1) == -1) {
        logg("!ScanStream: listen() error on socket. Error returned is %s.\n", strerror(errno));
        closesocket(sockfd);
        return -1;
    }
	if(mdprintf(odesc, "PORT %u%c", port, term) <= 0) {
	    logg("!ScanStream: error transmitting port.\n");
	    closesocket(sockfd);
	    return -1;
	}
    }

    retval = poll_fd(sockfd, firsttimeout, 0);
    if (!retval || retval == -1) {
	const char *reason = !retval ? "timeout" : "poll";
	mdprintf(odesc, "Accept %s. ERROR%c", reason, term);
	logg("!ScanStream %u: accept %s.\n", port, reason);
	closesocket(sockfd);
	return -1;
    }

    addrlen = sizeof(peer);
    if((acceptd = accept(sockfd, (struct sockaddr *) &peer, (socklen_t *)&addrlen)) == -1) {
	closesocket(sockfd);
	mdprintf(odesc, "accept() ERROR%c", term);
	logg("!ScanStream %u: accept() failed.\n", port);
	return -1;
    }

    *peer_addr = '\0';
    inet_ntop(peer.sin_family, &peer.sin_addr, peer_addr, sizeof(peer_addr));
    logg("*Accepted connection from %s on port %u, fd %d\n", peer_addr, port, acceptd);

    if(cli_gentempfd(optget(opts, "TemporaryDirectory")->strarg, &tmpname, &tmpd)) {
	shutdown(sockfd, 2);
	closesocket(sockfd);
	closesocket(acceptd);
	mdprintf(odesc, "cli_gentempfd() failed. ERROR%c", term);
	logg("!ScanStream(%s@%u): Can't create temporary file.\n", peer_addr, port);
	return -1;
    }

    quota = maxsize = optget(opts, "StreamMaxLength")->numarg;

    while((retval = poll_fd(acceptd, timeout, 0)) == 1) {
	/* only read up to max */
	btread = (maxsize && (quota < sizeof(buff))) ? quota : sizeof(buff);
	if (!btread) {
		logg("^ScanStream(%s@%u): Size limit reached (max: %lu)\n", peer_addr, port, maxsize);
		break; /* Scan what we have */
	}
	bread = recv(acceptd, buff, btread, 0);
	if(bread <= 0)
	    break;

	quota -= bread;

	if(writen(tmpd, buff, bread) != bread) {
	    shutdown(sockfd, 2);
	    closesocket(sockfd);
	    closesocket(acceptd);
	    mdprintf(odesc, "Temporary file -> write ERROR%c", term);
	    logg("!ScanStream(%s@%u): Can't write to temporary file.\n", peer_addr, port);
	    close(tmpd);
	    if(!optget(opts, "LeaveTemporaryFiles")->enabled)
		unlink(tmpname);
	    free(tmpname);
	    return -1;
	}
    }

    switch(retval) {
	case 0: /* timeout */
	    mdprintf(odesc, "read timeout ERROR%c", term);
	    logg("!ScanStream(%s@%u): read timeout.\n", peer_addr, port);
	    break;
	case -1:
	    mdprintf(odesc, "read poll ERROR%c", term);
	    logg("!ScanStream(%s@%u): read poll failed.\n", peer_addr, port);
	    break;
    }

    if(retval == 1) {
	lseek(tmpd, 0, SEEK_SET);
	thrmgr_setactivetask(peer_addr, NULL);
	context.filename = peer_addr;
	context.virsize = 0;
        context.scandata = NULL;
	ret = cl_scandesc_callback(tmpd, &virname, scanned, engine, options, &context);
	thrmgr_setactivetask(NULL, NULL);
    } else {
    	ret = -1;
    }
    close(tmpd);
    if(!optget(opts, "LeaveTemporaryFiles")->enabled)
	unlink(tmpname);
    free(tmpname);

    closesocket(acceptd);
    closesocket(sockfd);

    if(ret == CL_VIRUS) {
	if(context.virsize && optget(opts, "ExtendedDetectionInfo")->enabled) {
	    mdprintf(odesc, "stream: %s(%s:%llu) FOUND%c", virname, context.virhash, context.virsize, term);
	    logg("stream(%s@%u): %s(%s:%llu) FOUND\n", peer_addr, port, virname, context.virhash, context.virsize);
	} else {
	    mdprintf(odesc, "stream: %s FOUND%c", virname, term);
	    logg("stream(%s@%u): %s FOUND\n", peer_addr, port, virname);
	}
	virusaction("stream", virname, opts);
    } else if(ret != CL_CLEAN) {
    	if(retval == 1) {
	    mdprintf(odesc, "stream: %s ERROR%c", cl_strerror(ret), term);
	    logg("stream(%s@%u): %s ERROR\n", peer_addr, port, cl_strerror(ret));
	}
    } else {
	mdprintf(odesc, "stream: OK%c", term);
        if(logok)
	    logg("stream(%s@%u): OK\n", peer_addr, port); 
    }

    return ret;
}
Exemple #9
0
/* Read and dump a file for scanning */
static int hfsplus_scanfile(cli_ctx *ctx, hfsPlusVolumeHeader *volHeader, hfsHeaderRecord *extHeader,
    hfsPlusForkData *fork, const char *dirname)
{
    hfsPlusExtentDescriptor *currExt;
    const uint8_t *mPtr = NULL;
    char *tmpname = NULL;
    int ofd, ret = CL_CLEAN;
    uint64_t targetSize;
    uint32_t outputBlocks = 0;
    uint8_t ext;

    UNUSEDPARAM(extHeader);

    /* bad record checks */
    if (!fork || (fork->logicalSize == 0) || (fork->totalBlocks == 0)) {
        cli_dbgmsg("hfsplus_dumpfile: Empty file.\n");
        return CL_CLEAN;
    }

    /* check limits */
    targetSize = fork->logicalSize;
#if SIZEOF_LONG < 8
    if (targetSize > ULONG_MAX) {
        cli_dbgmsg("hfsplus_dumpfile: File too large for limit check.\n");
        return CL_EFORMAT;
    }
#endif
    ret = cli_checklimits("hfsplus_scanfile", ctx, (unsigned long)targetSize, 0, 0);
    if (ret != CL_CLEAN) {
        return ret;
    }

    /* open file */
    ret = cli_gentempfd(dirname, &tmpname, &ofd);
    if (ret != CL_CLEAN) {
        cli_dbgmsg("hfsplus_dumpfile: Cannot generate temporary file.\n");
        return ret;
    }
    cli_dbgmsg("hfsplus_dumpfile: Extracting to %s\n", tmpname);

    ext = 0;
    /* Dump file, extent by extent */
    do {
        uint32_t currBlock, endBlock, outputSize = 0;
        if (targetSize == 0) {
            cli_dbgmsg("hfsplus_dumpfile: output complete\n");
            break;
        }
        if (outputBlocks >= fork->totalBlocks) {
            cli_dbgmsg("hfsplus_dumpfile: output all blocks, remaining size " STDu64 "\n", targetSize);
            break;
        }
        /* Prepare extent */
        if (ext < 8) {
            currExt = &(fork->extents[ext]);
            cli_dbgmsg("hfsplus_dumpfile: extent %u\n", ext);
        }
        else {
            cli_dbgmsg("hfsplus_dumpfile: need next extent from ExtentOverflow\n");
            /* Not implemented yet */
            ret = CL_EFORMAT;
            break;
        }
        /* have extent, so validate and get block range */
        if ((currExt->startBlock == 0) || (currExt->blockCount == 0)) {
            cli_dbgmsg("hfsplus_dumpfile: next extent empty, done\n");
            break;
        }
        if ((currExt->startBlock & 0x10000000) && (currExt->blockCount & 0x10000000)) {
            cli_dbgmsg("hfsplus_dumpfile: next extent illegal!\n");
            ret = CL_EFORMAT;
            break;
        }
        currBlock = currExt->startBlock;
        endBlock = currExt->startBlock + currExt->blockCount - 1;
        if ((currBlock > volHeader->totalBlocks) || (endBlock > volHeader->totalBlocks)
                || (currExt->blockCount > volHeader->totalBlocks)) {
            cli_dbgmsg("hfsplus_dumpfile: bad extent!\n");
            ret = CL_EFORMAT;
            break;
        }
        /* Write the blocks, walking the map */
        while (currBlock <= endBlock) {
            size_t to_write = MIN(targetSize, volHeader->blockSize);
            ssize_t written;
            off_t offset = currBlock * volHeader->blockSize;
            /* move map to next block */
            mPtr = fmap_need_off_once(*ctx->fmap, offset, volHeader->blockSize);
            if (!mPtr) {
                cli_errmsg("hfsplus_dumpfile: map error\n");
                ret = CL_EMAP;
                break;
            }
            written = cli_writen(ofd, mPtr, to_write);
            if ((size_t)written != to_write) {
                cli_errmsg("hfsplus_dumpfile: write error\n");
                ret = CL_EWRITE;
                break;
            }
            targetSize -= to_write;
            outputSize += to_write;
            currBlock++;
            if (targetSize == 0) {
                cli_dbgmsg("hfsplus_dumpfile: all data written\n");
                break;
            }
            if (outputBlocks >= fork->totalBlocks) {
                cli_dbgmsg("hfsplus_dumpfile: output all blocks, remaining size " STDu64 "\n", targetSize);
                break;
            }
        }
        /* Finished the extent, move to next */
        ext++;
    } while (ret == CL_CLEAN);

    /* if successful so far, scan the output */
    if (ret == CL_CLEAN) {
        ret = cli_magic_scandesc(ofd, tmpname, ctx);
    }

    if (ofd >= 0) {
        close(ofd);
    }
    if (!ctx->engine->keeptmp) {
        if (cli_unlink(tmpname)) {
            ret = CL_EUNLINK;
        }
    }
    free(tmpname);

    return ret;
}
Exemple #10
0
int cli_scanxar(cli_ctx *ctx)
{
    int rc = CL_SUCCESS;
    unsigned int cksum_fails = 0;
    unsigned int extract_errors = 0;
#if HAVE_LIBXML2
    int fd = -1;
    struct xar_header hdr;
    fmap_t *map = *ctx->fmap;
    long length, offset, size, at;
    int encoding;
    z_stream strm;
    char *toc, *tmpname;
    xmlTextReaderPtr reader = NULL;
    int a_hash, e_hash;
    unsigned char *a_cksum = NULL, *e_cksum = NULL;

    memset(&strm, 0x00, sizeof(z_stream));

    /* retrieve xar header */
    if (fmap_readn(*ctx->fmap, &hdr, 0, sizeof(hdr)) != sizeof(hdr)) {
        cli_dbgmsg("cli_scanxar: Invalid header, too short.\n");
        return CL_EFORMAT;
    }
    hdr.magic = be32_to_host(hdr.magic);

    if (hdr.magic == XAR_HEADER_MAGIC) {
        cli_dbgmsg("cli_scanxar: Matched magic\n");
    }
    else {
        cli_dbgmsg("cli_scanxar: Invalid magic\n");
        return CL_EFORMAT;
    }
    hdr.size = be16_to_host(hdr.size);
    hdr.version = be16_to_host(hdr.version);
    hdr.toc_length_compressed = be64_to_host(hdr.toc_length_compressed);
    hdr.toc_length_decompressed = be64_to_host(hdr.toc_length_decompressed);
    hdr.chksum_alg = be32_to_host(hdr.chksum_alg);

    /* cli_dbgmsg("hdr.magic %x\n", hdr.magic); */
    /* cli_dbgmsg("hdr.size %i\n", hdr.size); */
    /* cli_dbgmsg("hdr.version %i\n", hdr.version); */
    /* cli_dbgmsg("hdr.toc_length_compressed %lu\n", hdr.toc_length_compressed); */
    /* cli_dbgmsg("hdr.toc_length_decompressed %lu\n", hdr.toc_length_decompressed); */
    /* cli_dbgmsg("hdr.chksum_alg %i\n", hdr.chksum_alg); */

    /* Uncompress TOC */
    strm.next_in = (unsigned char *)fmap_need_off_once(*ctx->fmap, hdr.size, hdr.toc_length_compressed);
    if (strm.next_in == NULL) {
        cli_dbgmsg("cli_scanxar: fmap_need_off_once fails on TOC.\n");
        return CL_EREAD;
    }
    strm.avail_in = hdr.toc_length_compressed;
    toc = cli_malloc(hdr.toc_length_decompressed+1);
    if (toc == NULL) {
        cli_dbgmsg("cli_scanxar: cli_malloc fails on TOC decompress buffer.\n");
        return CL_EMEM;
    }
    toc[hdr.toc_length_decompressed] = '\0';
    strm.avail_out = hdr.toc_length_decompressed;
    strm.next_out = (unsigned char *)toc;
    rc = inflateInit(&strm);
    if (rc != Z_OK) {
        cli_dbgmsg("cli_scanxar:inflateInit error %i \n", rc);
        rc = CL_EFORMAT;
        goto exit_toc;
    }
    rc = inflate(&strm, Z_SYNC_FLUSH);
    if (rc != Z_OK && rc != Z_STREAM_END) {
        cli_dbgmsg("cli_scanxar:inflate error %i \n", rc);
        rc = CL_EFORMAT;
        goto exit_toc;
    }
    rc = inflateEnd(&strm);
    if (rc != Z_OK) {
        cli_dbgmsg("cli_scanxar:inflateEnd error %i \n", rc);
        rc = CL_EFORMAT;
        goto exit_toc;
    }

    /* cli_dbgmsg("cli_scanxar: TOC xml:\n%s\n", toc); */
    /* printf("cli_scanxar: TOC xml:\n%s\n", toc); */
    /* cli_dbgmsg("cli_scanxar: TOC end:\n"); */
    /* printf("cli_scanxar: TOC end:\n"); */

    /* scan the xml */
    cli_dbgmsg("cli_scanxar: scanning xar TOC xml in memory.\n");
    rc = cli_mem_scandesc(toc, hdr.toc_length_decompressed, ctx);
    if (rc != CL_SUCCESS) {
        if (rc != CL_VIRUS || !SCAN_ALL)
            goto exit_toc;
    }

    /* make a file to leave if --leave-temps in effect */
    if(ctx->engine->keeptmp) {
        if ((rc = cli_gentempfd(ctx->engine->tmpdir, &tmpname, &fd)) != CL_SUCCESS) {
            cli_dbgmsg("cli_scanxar: Can't create temporary file for TOC.\n");
            goto exit_toc;
        }
        if (cli_writen(fd, toc, hdr.toc_length_decompressed) < 0) {
            cli_dbgmsg("cli_scanxar: cli_writen error writing TOC.\n");
            rc = CL_EWRITE;
            xar_cleanup_temp_file(ctx, fd, tmpname);
            goto exit_toc;
        }
        rc = xar_cleanup_temp_file(ctx, fd, tmpname);
        if (rc != CL_SUCCESS)
            goto exit_toc;
    }

    reader = xmlReaderForMemory(toc, hdr.toc_length_decompressed, "noname.xml", NULL, 0);
    if (reader == NULL) {
        cli_dbgmsg("cli_scanxar: xmlReaderForMemory error for TOC\n");
        goto exit_toc;
    }

    rc = xar_scan_subdocuments(reader, ctx);
    if (rc != CL_SUCCESS) {
        cli_dbgmsg("xar_scan_subdocuments returns %i.\n", rc);
        goto exit_reader;
    }

    /* Walk the TOC XML and extract files */
    fd = -1;
    tmpname = NULL;
    while (CL_SUCCESS == (rc = xar_get_toc_data_values(reader, &length, &offset, &size, &encoding,
                               &a_cksum, &a_hash, &e_cksum, &e_hash))) {
        int do_extract_cksum = 1;
        unsigned char * blockp;
        void *a_sc, *e_sc;
        void *a_mc, *e_mc;
        void *a_hash_ctx, *e_hash_ctx;
        char result[SHA1_HASH_SIZE];
        char * expected;

        /* clean up temp file from previous loop iteration */
        if (fd > -1 && tmpname) {
            rc = xar_cleanup_temp_file(ctx, fd, tmpname);
            if (rc != CL_SUCCESS)
                goto exit_reader;
        }

        at = offset + hdr.toc_length_compressed + hdr.size;

        if ((rc = cli_gentempfd(ctx->engine->tmpdir, &tmpname, &fd)) != CL_SUCCESS) {
            cli_dbgmsg("cli_scanxar: Can't generate temporary file.\n");
            goto exit_reader;
        }

        cli_dbgmsg("cli_scanxar: decompress into temp file:\n%s, size %li,\n"
                   "from xar heap offset %li length %li\n",
                   tmpname, size, offset, length);


        a_hash_ctx = xar_hash_init(a_hash, &a_sc, &a_mc);
        e_hash_ctx = xar_hash_init(e_hash, &e_sc, &e_mc);

        switch (encoding) {
        case CL_TYPE_GZ:
            /* inflate gzip directly because file segments do not contain magic */
            memset(&strm, 0, sizeof(strm));
            if ((rc = inflateInit(&strm)) != Z_OK) {
                cli_dbgmsg("cli_scanxar: InflateInit failed: %d\n", rc);
                rc = CL_EFORMAT;
                extract_errors++;
                break;
            }

            while ((size_t)at < map->len && (unsigned long)at < offset+hdr.toc_length_compressed+hdr.size+length) {
                unsigned long avail_in;
                void * next_in;
                unsigned int bytes = MIN(map->len - at, map->pgsz);
                bytes = MIN(length, bytes);
                if(!(strm.next_in = next_in = (void*)fmap_need_off_once(map, at, bytes))) {
                    cli_dbgmsg("cli_scanxar: Can't read %u bytes @ %lu.\n", bytes, (long unsigned)at);
                    inflateEnd(&strm);
                    rc = CL_EREAD;
                    goto exit_tmpfile;
                }
                at += bytes;
                strm.avail_in = avail_in = bytes;
                do {
                    int inf, outsize = 0;
                    unsigned char buff[FILEBUFF];
                    strm.avail_out = sizeof(buff);
                    strm.next_out = buff;
                    inf = inflate(&strm, Z_SYNC_FLUSH);
                    if (inf != Z_OK && inf != Z_STREAM_END && inf != Z_BUF_ERROR) {
                        cli_dbgmsg("cli_scanxar: inflate error %i %s.\n", inf, strm.msg?strm.msg:"");
                        rc = CL_EFORMAT;
                        extract_errors++;
                        break;
                    }

                    bytes = sizeof(buff) - strm.avail_out;

                    xar_hash_update(e_hash_ctx, buff, bytes, e_hash);

                    if (cli_writen(fd, buff, bytes) < 0) {
                        cli_dbgmsg("cli_scanxar: cli_writen error file %s.\n", tmpname);
                        inflateEnd(&strm);
                        rc = CL_EWRITE;
                        goto exit_tmpfile;
                    }
                    outsize += sizeof(buff) - strm.avail_out;
                    if (cli_checklimits("cli_scanxar", ctx, outsize, 0, 0) != CL_CLEAN) {
                        break;
                    }
                    if (inf == Z_STREAM_END) {
                        break;
                    }
                } while (strm.avail_out == 0);

                if (rc != CL_SUCCESS)
                    break;

                avail_in -= strm.avail_in;
                xar_hash_update(a_hash_ctx, next_in, avail_in, a_hash);
            }

            inflateEnd(&strm);
            break;
        case CL_TYPE_7Z:
#define CLI_LZMA_OBUF_SIZE 1024*1024
#define CLI_LZMA_HDR_SIZE LZMA_PROPS_SIZE+8
#define CLI_LZMA_IBUF_SIZE CLI_LZMA_OBUF_SIZE>>2 /* estimated compression ratio 25% */
        {
            struct CLI_LZMA lz;
            unsigned long in_remaining = length;
            unsigned long out_size = 0;
            unsigned char * buff = __lzma_wrap_alloc(NULL, CLI_LZMA_OBUF_SIZE);
            int lret;

            memset(&lz, 0, sizeof(lz));
            if (buff == NULL) {
                cli_dbgmsg("cli_scanxar: memory request for lzma decompression buffer fails.\n");
                rc = CL_EMEM;
                goto exit_tmpfile;

            }

            blockp = (void*)fmap_need_off_once(map, at, CLI_LZMA_HDR_SIZE);
            if (blockp == NULL) {
                char errbuff[128];
                cli_strerror(errno, errbuff, sizeof(errbuff));
                cli_dbgmsg("cli_scanxar: Can't read %li bytes @ %li, errno:%s.\n",
                           length, at, errbuff);
                rc = CL_EREAD;
                __lzma_wrap_free(NULL, buff);
                goto exit_tmpfile;
            }

            lz.next_in = blockp;
            lz.avail_in = CLI_LZMA_HDR_SIZE;

            xar_hash_update(a_hash_ctx, blockp, CLI_LZMA_HDR_SIZE, a_hash);

            lret = cli_LzmaInit(&lz, 0);
            if (lret != LZMA_RESULT_OK) {
                cli_dbgmsg("cli_scanxar: cli_LzmaInit() fails: %i.\n", lret);
                rc = CL_EFORMAT;
                __lzma_wrap_free(NULL, buff);
                extract_errors++;
                break;
            }

            at += CLI_LZMA_HDR_SIZE;
            in_remaining -= CLI_LZMA_HDR_SIZE;
            while ((size_t)at < map->len && (unsigned long)at < offset+hdr.toc_length_compressed+hdr.size+length) {
                SizeT avail_in;
                SizeT avail_out;
                void * next_in;
                unsigned long in_consumed;

                lz.next_out = buff;
                lz.avail_out = CLI_LZMA_OBUF_SIZE;
                lz.avail_in = avail_in = MIN(CLI_LZMA_IBUF_SIZE, in_remaining);
                lz.next_in = next_in = (void*)fmap_need_off_once(map, at, lz.avail_in);
                if (lz.next_in == NULL) {
                    char errbuff[128];
                    cli_strerror(errno, errbuff, sizeof(errbuff));
                    cli_dbgmsg("cli_scanxar: Can't read %li bytes @ %li, errno: %s.\n",
                               length, at, errbuff);
                    rc = CL_EREAD;
                    __lzma_wrap_free(NULL, buff);
                    cli_LzmaShutdown(&lz);
                    goto exit_tmpfile;
                }

                lret = cli_LzmaDecode(&lz);
                if (lret != LZMA_RESULT_OK && lret != LZMA_STREAM_END) {
                    cli_dbgmsg("cli_scanxar: cli_LzmaDecode() fails: %i.\n", lret);
                    rc = CL_EFORMAT;
                    extract_errors++;
                    break;
                }

                in_consumed = avail_in - lz.avail_in;
                in_remaining -= in_consumed;
                at += in_consumed;
                avail_out = CLI_LZMA_OBUF_SIZE - lz.avail_out;

                if (avail_out == 0)
                    cli_dbgmsg("cli_scanxar: cli_LzmaDecode() produces no output for "
                               "avail_in %lu, avail_out %lu.\n", avail_in, avail_out);

                xar_hash_update(a_hash_ctx, next_in, in_consumed, a_hash);
                xar_hash_update(e_hash_ctx, buff, avail_out, e_hash);

                /* Write a decompressed block. */
                /* cli_dbgmsg("Writing %li bytes to LZMA decompress temp file, " */
                /*            "consumed %li of %li available compressed bytes.\n", */
                /*            avail_out, in_consumed, avail_in); */

                if (cli_writen(fd, buff, avail_out) < 0) {
                    cli_dbgmsg("cli_scanxar: cli_writen error writing lzma temp file for %li bytes.\n",
                               avail_out);
                    __lzma_wrap_free(NULL, buff);
                    cli_LzmaShutdown(&lz);
                    rc = CL_EWRITE;
                    goto exit_tmpfile;
                }

                /* Check file size limitation. */
                out_size += avail_out;
                if (cli_checklimits("cli_scanxar", ctx, out_size, 0, 0) != CL_CLEAN) {
                    break;
                }

                if (lret == LZMA_STREAM_END)
                    break;
            }

            cli_LzmaShutdown(&lz);
            __lzma_wrap_free(NULL, buff);
        }
        break;
        case CL_TYPE_ANY:
        default:
        case CL_TYPE_BZ:
        case CL_TYPE_XZ:
            /* for uncompressed, bzip2, xz, and unknown, just pull the file, cli_magic_scandesc does the rest */
            do_extract_cksum = 0;
            {
                unsigned long write_len;

                if (ctx->engine->maxfilesize)
                    write_len = MIN((size_t)(ctx->engine->maxfilesize), (size_t)length);
                else
                    write_len = length;

                if (!(blockp = (void*)fmap_need_off_once(map, at, length))) {
                    char errbuff[128];
                    cli_strerror(errno, errbuff, sizeof(errbuff));
                    cli_dbgmsg("cli_scanxar: Can't read %li bytes @ %li, errno:%s.\n",
                               length, at, errbuff);
                    rc = CL_EREAD;
                    goto exit_tmpfile;
                }

                xar_hash_update(a_hash_ctx, blockp, length, a_hash);

                if (cli_writen(fd, blockp, write_len) < 0) {
                    cli_dbgmsg("cli_scanxar: cli_writen error %li bytes @ %li.\n", length, at);
                    rc = CL_EWRITE;
                    goto exit_tmpfile;
                }
                /*break;*/
            }
        }

        if (rc == CL_SUCCESS) {
            xar_hash_final(a_hash_ctx, result, a_hash);
            if (a_cksum != NULL) {
                expected = cli_hex2str((char *)a_cksum);
                if (xar_hash_check(a_hash, result, expected) != 0) {
                    cli_dbgmsg("cli_scanxar: archived-checksum missing or mismatch.\n");
                    cksum_fails++;
                } else {
                    cli_dbgmsg("cli_scanxar: archived-checksum matched.\n");
                }
                free(expected);
            }
            if (e_cksum != NULL) {
                if (do_extract_cksum) {
                    xar_hash_final(e_hash_ctx, result, e_hash);
                    expected = cli_hex2str((char *)e_cksum);
                    if (xar_hash_check(e_hash, result, expected) != 0) {
                        cli_dbgmsg("cli_scanxar: extracted-checksum missing or mismatch.\n");
                        cksum_fails++;
                    } else {
                        cli_dbgmsg("cli_scanxar: extracted-checksum matched.\n");
                    }
                    free(expected);
                }
            }

            rc = cli_magic_scandesc(fd, ctx);
            if (rc != CL_SUCCESS) {
                if (rc == CL_VIRUS) {
                    cli_dbgmsg("cli_scanxar: Infected with %s\n", cli_get_last_virus(ctx));
                    if (!SCAN_ALL)
                        goto exit_tmpfile;
                } else if (rc != CL_BREAK) {
                    cli_dbgmsg("cli_scanxar: cli_magic_scandesc error %i\n", rc);
                    goto exit_tmpfile;
                }
            }
        }

        if (a_cksum != NULL) {
            xmlFree(a_cksum);
            a_cksum = NULL;
        }
        if (e_cksum != NULL) {
            xmlFree(e_cksum);
            e_cksum = NULL;
        }
    }

exit_tmpfile:
    xar_cleanup_temp_file(ctx, fd, tmpname);

exit_reader:
    if (a_cksum != NULL)
        xmlFree(a_cksum);
    if (e_cksum != NULL)
        xmlFree(e_cksum);
    xmlTextReaderClose(reader);
    xmlFreeTextReader(reader);

exit_toc:
    free(toc);
    if (rc == CL_BREAK)
        rc = CL_SUCCESS;
#else
    cli_dbgmsg("cli_scanxar: can't scan xar files, need libxml2.\n");
#endif
    if (cksum_fails + extract_errors != 0) {
        cli_warnmsg("cli_scanxar: %u checksum errors and %u extraction errors, use --debug for more info.\n",
                    cksum_fails, extract_errors);
    }

    return rc;
}
Exemple #11
0
static int rtf_object_process(struct rtf_state* state, const unsigned char* input,const size_t len)
{
	struct rtf_object_data* data = state->cb_data;
	unsigned char outdata[BUFF_SIZE];
	const unsigned char* out_data;
	size_t out_cnt = 0;
	size_t i;
	int ret;

	if(!data || !len)
		return 0;

	if(data->has_partial) {
		for(i=0;i<len && !isxdigit(input[i]);i++)
			;
		if(i<len) {
			outdata[out_cnt++] = data->partial | hextable[input[i++]];
			data->has_partial = 0;
		}
		else
			return 0;
	}
	else
		i = 0;

	for(;i<len;i++) {
		if(isxdigit(input[i])) {
				const unsigned char byte = hextable[ input[i++] ] << 4;
				while(i<len && !isxdigit(input[i]))
					i++;
				if(i == len) {
					data->partial = byte;
					data->has_partial = 1;
					break;
				}
				outdata[out_cnt++] = byte | hextable[ input[i] ];
		}
	}

	out_data = outdata;
	while(out_data && out_cnt) {
		switch(data->internal_state) {
			case WAIT_MAGIC: {
						 cli_dbgmsg("RTF: waiting for magic\n");
						 for(i=0; i<out_cnt && data->bread < rtf_data_magic_len; i++, data->bread++)
							 if(rtf_data_magic[data->bread] != out_data[i]) {
								 cli_dbgmsg("Warning: rtf objdata magic number not matched, expected:%d, got: %d, at pos:%lu\n",rtf_data_magic[i],out_data[i], (unsigned long int) data->bread);
							 }
						 out_cnt  -= i;
						 if(data->bread == rtf_data_magic_len) {
							 out_data += i;
							 data->bread = 0;
							 data->internal_state = WAIT_DESC_LEN;						 
						 }
						 break;
					 }
			case WAIT_DESC_LEN: {
						    if(data->bread == 0)
							    data->desc_len = 0;
						    for(i=0; i<out_cnt && data->bread < 4; i++,data->bread++)
							    data->desc_len  |=  ((size_t)out_data[i]) << (data->bread*8);
						    out_cnt  -= i;
						    if(data->bread == 4) {
							    out_data += i;
							    data->bread=0;
							    if(data->desc_len > 64) {
								    cli_dbgmsg("Description length too big (%lu), showing only 64 bytes of it\n", (unsigned long int) data->desc_len);
								    data->desc_name = cli_malloc(65);
							    }
							    else
								    data->desc_name = cli_malloc(data->desc_len+1);
							    if(!data->desc_name) {
                                    cli_errmsg("rtf_object_process: Unable to allocate memory for data->desc_name\n");
								    return CL_EMEM;
							    }
							    data->internal_state = WAIT_DESC;
							    cli_dbgmsg("RTF: description length:%lu\n", (unsigned long int) data->desc_len);
						    }
						    break;
					    }
			case WAIT_DESC:{
					       cli_dbgmsg("RTF: in WAIT_DESC\n");
					       for(i=0;i<out_cnt && data->bread < data->desc_len && data->bread < 64;i++, data->bread++)
						       data->desc_name[data->bread] = out_data[i];
					       out_cnt -= i;
					       out_data += i;
					       if(data->bread < data->desc_len && data->bread < 64) {
						       cli_dbgmsg("RTF: waiting for more data(1)\n");
						       return 0;/* wait for more data */
					       }
						       data->desc_name[data->bread] = '\0';
					       if(data->desc_len - data->bread > out_cnt) {
						       data->desc_len -= out_cnt;
						       cli_dbgmsg("RTF: waiting for more data(2)\n");
						       return 0;/* wait for more data */
					       }
					       out_cnt  -= data->desc_len - data->bread;
					       if(data->bread >= data->desc_len) {
						       out_data += data->desc_len - data->bread;
						       data->bread = 0;
						       cli_dbgmsg("Preparing to dump rtf embedded object, description:%s\n",data->desc_name);
						       free(data->desc_name);
						       data->desc_name = NULL;
						       data->internal_state = WAIT_ZERO;
					       }
					       break;
				       }
			case WAIT_ZERO:{
					       if(out_cnt < 8-data->bread) {
						       out_cnt = 0;
						       data->bread += out_cnt;
					       }
					       else {
						       out_cnt  -= 8-data->bread;
						       data->bread = 8;
					       }
					       if(data->bread == 8) {
						       out_data += 8;
						       data->bread = 0;
						       cli_dbgmsg("RTF: next state: wait_data_size\n");
						       data->internal_state = WAIT_DATA_SIZE;
					       }
					       break;
				       }

			case WAIT_DATA_SIZE: {
						     cli_dbgmsg("RTF: in WAIT_DATA_SIZE\n");
						    if(data->bread == 0)
							    data->desc_len = 0;
						    for(i=0; i<out_cnt && data->bread < 4; i++,data->bread++)
							    data->desc_len  |= ((size_t)out_data[i]) << (8*data->bread);
						    out_cnt  -= i;
						    if(data->bread == 4) {
							    out_data += i;
							    data->bread=0;
							    cli_dbgmsg("Dumping rtf embedded object of size:%lu\n", (unsigned long int) data->desc_len);
							    if((ret = cli_gentempfd(data->tmpdir, &data->name, &data->fd)))
								    return ret;
							    data->internal_state = DUMP_DATA;
	    						    cli_dbgmsg("RTF: next state: DUMP_DATA\n");
						    }
						    break;
					     }
			case DUMP_DATA: {
						ssize_t out_want = out_cnt < data->desc_len ? out_cnt : data->desc_len;
						if(!data->bread) {
							if(out_data[0] != 0xd0 || out_data[1]!=0xcf) {
								/* this is not an ole2 doc, but some ole (stream?) to be
								 * decoded by cli_decode_ole_object*/
							    char out[4];
							    data->bread = 1;/* flag to indicate this needs to be scanned with cli_decode_ole_object*/
							    cli_writeint32(out,data->desc_len);
							    if(cli_writen(data->fd,out,4)!=4)
								    return CL_EWRITE; 
							}
							else
								data->bread = 2;
						}

						data->desc_len -= out_want;
						if(cli_writen(data->fd,out_data,out_want) != out_want) {
							return CL_EWRITE;
						}
						out_data += out_want;
						out_cnt  -= out_want;
						if(!data->desc_len) { 
							int rc;
							if(( rc = decode_and_scan(data, data->ctx) ))
								return rc;
							data->bread=0;
							data->internal_state = WAIT_MAGIC;
						}
						break;					
					}				    
			case DUMP_DISCARD:
			default:
					out_cnt = 0;
					;
		}
	}
	return 0;
}
Exemple #12
0
static int scancws(cli_ctx *ctx, struct swf_file_hdr *hdr)
{
        z_stream stream;
        char inbuff[FILEBUFF], outbuff[FILEBUFF];
        fmap_t *map = *ctx->fmap;
        int offset = 8, ret, zret, outsize = 8, count, zend;
        char *tmpname;
        int fd;

    if((ret = cli_gentempfd(ctx->engine->tmpdir, &tmpname, &fd)) != CL_SUCCESS) {
        cli_errmsg("scancws: Can't generate temporary file\n");
        return ret;
    }

    hdr->signature[0] = 'F';
    if(cli_writen(fd, hdr, sizeof(struct swf_file_hdr)) != sizeof(struct swf_file_hdr)) {
        cli_errmsg("scancws: Can't write to file %s\n", tmpname);
        close(fd);
        if(cli_unlink(tmpname)) {
            free(tmpname);
            return CL_EUNLINK;
        }
        free(tmpname);
        return CL_EWRITE;
    }

    stream.avail_in = 0;
    stream.next_in = (Bytef *)inbuff;
    stream.next_out = (Bytef *)outbuff;
    stream.zalloc = (alloc_func) NULL;
    stream.zfree = (free_func) NULL;
    stream.opaque = (voidpf) 0;
    stream.avail_out = FILEBUFF;

    zret = inflateInit(&stream);
    if(zret != Z_OK) {
        cli_errmsg("scancws: inflateInit() failed\n");
        close(fd);
        if(cli_unlink(tmpname)) {
            free(tmpname);
            return CL_EUNLINK;
        }
        free(tmpname);
        return CL_EUNPACK;
    }

    do {
        if(stream.avail_in == 0) {
            stream.next_in = (Bytef *)inbuff;
            ret = fmap_readn(map, inbuff, offset, FILEBUFF);
            if(ret < 0) {
                cli_errmsg("scancws: Error reading SWF file\n");
                close(fd);
                inflateEnd(&stream);
                if(cli_unlink(tmpname)) {
                    free(tmpname);
                    return CL_EUNLINK;
                }
                free(tmpname);
                return CL_EUNPACK;
            }
            if(!ret)
                break;
            stream.avail_in = ret;
            offset += ret;
        }
        zret = inflate(&stream, Z_SYNC_FLUSH);
        count = FILEBUFF - stream.avail_out;
        if(count) {
            if(cli_checklimits("SWF", ctx, outsize + count, 0, 0) != CL_SUCCESS)
                break;
            if(cli_writen(fd, outbuff, count) != count) {
                cli_errmsg("scancws: Can't write to file %s\n", tmpname);
                inflateEnd(&stream);
                close(fd);
                if(cli_unlink(tmpname)) {
                    free(tmpname);
                    return CL_EUNLINK;
                }
                free(tmpname);
                return CL_EWRITE;
            }
            outsize += count;
        }
        stream.next_out = (Bytef *)outbuff;
        stream.avail_out = FILEBUFF;
    } while(zret == Z_OK);

    zend = inflateEnd(&stream);

    if((zret != Z_STREAM_END && zret != Z_OK) || zend != Z_OK) {
        /*
         * outsize is initialized to 8, it being 8 here means that we couldn't even read a single byte.
         * If outsize > 8, then we have data. Let's scan what we have.
         */
        if (outsize == 8) {
            cli_infomsg(ctx, "scancws: Error decompressing SWF file. No data decompressed.\n");
            close(fd);
            if(cli_unlink(tmpname)) {
                free(tmpname);
                return CL_EUNLINK;
            }
            free(tmpname);
            return CL_EUNPACK;
        }
        cli_infomsg(ctx, "scancws: Error decompressing SWF file. Scanning what was decompressed.\n");
    }
    cli_dbgmsg("SWF: Decompressed[zlib] to %s, size %d\n", tmpname, outsize);

    /* check if declared output size matches actual output size */
    if (hdr->filesize != outsize) {
        cli_warnmsg("SWF: declared output length != inflated stream size, %u != %llu\n",
                    hdr->filesize, (long long unsigned)outsize);
    } else {
        cli_dbgmsg("SWF: declared output length == inflated stream size, %u == %llu\n",
                   hdr->filesize, (long long unsigned)outsize);
    }

    ret = cli_magic_scandesc(fd, ctx);

    close(fd);
    if(!ctx->engine->keeptmp) {
        if(cli_unlink(tmpname)) {
            free(tmpname);
            return CL_EUNLINK;
        }
    }
    free(tmpname);
    return ret;
}
Exemple #13
0
static int scanzws(cli_ctx *ctx, struct swf_file_hdr *hdr)
{
        struct CLI_LZMA lz;
        unsigned char inbuff[FILEBUFF], outbuff[FILEBUFF];
        fmap_t *map = *ctx->fmap;
        /* strip off header */
        off_t offset = 8;
        uint32_t d_insize;
        size_t outsize = 8;
        int ret, lret, count;
        char *tmpname;
        int fd;

    if((ret = cli_gentempfd(ctx->engine->tmpdir, &tmpname, &fd)) != CL_SUCCESS) {
        cli_errmsg("scanzws: Can't generate temporary file\n");
        return ret;
    }

    hdr->signature[0] = 'F';
    if(cli_writen(fd, hdr, sizeof(struct swf_file_hdr)) != sizeof(struct swf_file_hdr)) {
        cli_errmsg("scanzws: Can't write to file %s\n", tmpname);
        close(fd);
        if(cli_unlink(tmpname)) {
            free(tmpname);
            return CL_EUNLINK;
        }
        free(tmpname);
        return CL_EWRITE;
    }

    /* read 4 bytes (for compressed 32-bit filesize) [not used for LZMA] */
    if (fmap_readn(map, &d_insize, offset, sizeof(d_insize)) != sizeof(d_insize)) {
        cli_errmsg("scanzws: Error reading SWF file\n");
        close(fd);
        if (cli_unlink(tmpname)) {
            free(tmpname);
            return CL_EUNLINK;
        }
        free(tmpname);
        return CL_EREAD;
    }
    offset += sizeof(d_insize);

    /* check if declared input size matches actual output size */
    /* map->len = header (8 bytes) + d_insize (4 bytes) + flags (5 bytes) + compressed stream */
    if (d_insize != (map->len - 17)) {
        cli_warnmsg("SWF: declared input length != compressed stream size, %u != %llu\n",
                    d_insize, (long long unsigned)(map->len - 17));
    } else {
        cli_dbgmsg("SWF: declared input length == compressed stream size, %u == %llu\n",
                    d_insize, (long long unsigned)(map->len - 17));
    }

    /* first buffer required for initializing LZMA */
    ret = fmap_readn(map, inbuff, offset, FILEBUFF);
    if (ret < 0) {
        cli_errmsg("scanzws: Error reading SWF file\n");
        close(fd);
        if (cli_unlink(tmpname)) {
            free(tmpname);
            return CL_EUNLINK;
        }
        free(tmpname);
        return CL_EUNPACK;
    }
    /* nothing written, likely truncated */
    if (!ret) {
        cli_errmsg("scanzws: possibly truncated file\n");
        close(fd);
        if (cli_unlink(tmpname)) {
            free(tmpname);
            return CL_EUNLINK;
        }
        free(tmpname);
        return CL_EFORMAT;
    }
    offset += ret;

    memset(&lz, 0, sizeof(lz));
    lz.next_in = inbuff;
    lz.next_out = outbuff;
    lz.avail_in = ret;
    lz.avail_out = FILEBUFF;

    lret = cli_LzmaInit(&lz, hdr->filesize);
    if (lret != LZMA_RESULT_OK) {
        cli_errmsg("scanzws: LzmaInit() failed\n");
        close(fd);
        if (cli_unlink(tmpname)) {
            free(tmpname);
            return CL_EUNLINK;
        }
        free(tmpname);
        return CL_EUNPACK;
    }

    while (lret == LZMA_RESULT_OK) {
        if (lz.avail_in == 0) {
            lz.next_in = inbuff;

            ret = fmap_readn(map, inbuff, offset, FILEBUFF);
            if (ret < 0) {
                cli_errmsg("scanzws: Error reading SWF file\n");
                cli_LzmaShutdown(&lz);
                close(fd);
                if (cli_unlink(tmpname)) {
                    free(tmpname);
                    return CL_EUNLINK;
                }
                free(tmpname);
                return CL_EUNPACK;
            }
            if (!ret)
                break;
            lz.avail_in = ret;
            offset += ret;
        }
        lret = cli_LzmaDecode(&lz);
        count = FILEBUFF - lz.avail_out;
        if (count) {
            if (cli_checklimits("SWF", ctx, outsize + count, 0, 0) != CL_SUCCESS)
                break;
            if (cli_writen(fd, outbuff, count) != count) {
                cli_errmsg("scanzws: Can't write to file %s\n", tmpname);
                cli_LzmaShutdown(&lz);
                close(fd);
                if (cli_unlink(tmpname)) {
                    free(tmpname);
                    return CL_EUNLINK;
                }
                free(tmpname);
                return CL_EWRITE;
            }
            outsize += count;
        }
        lz.next_out = outbuff;
        lz.avail_out = FILEBUFF;
    }

    cli_LzmaShutdown(&lz);

    if (lret != LZMA_STREAM_END && lret != LZMA_RESULT_OK) {
        /* outsize starts at 8, therefore, if its still 8, nothing was decompressed */
        if (outsize == 8) {
            cli_infomsg(ctx, "scanzws: Error decompressing SWF file. No data decompressed.\n");
            close(fd);
            if (cli_unlink(tmpname)) {
                free(tmpname);
                return CL_EUNLINK;
            }
            free(tmpname);
            return CL_EUNPACK;
        }
        cli_infomsg(ctx, "scanzws: Error decompressing SWF file. Scanning what was decompressed.\n");
    }
    cli_dbgmsg("SWF: Decompressed[LZMA] to %s, size %llu\n", tmpname, (long long unsigned)outsize);

    /* check if declared output size matches actual output size */
    if (hdr->filesize != outsize) {
        cli_warnmsg("SWF: declared output length != inflated stream size, %u != %llu\n",
                    hdr->filesize, (long long unsigned)outsize);
    } else {
        cli_dbgmsg("SWF: declared output length == inflated stream size, %u == %llu\n",
                   hdr->filesize, (long long unsigned)outsize);
    }

    ret = cli_magic_scandesc(fd, ctx);

    close(fd);
    if (!(ctx->engine->keeptmp)) {
        if (cli_unlink(tmpname)) {
            free(tmpname);
            return CL_EUNLINK;
        }
    }
    free(tmpname);
    return ret;
}