Example #1
0
END_TEST

START_TEST (test_cl_scanfile_callback_allscan)
{
    const char *virname = NULL;
    const char **virpp = &virname;
    char file[256];
    unsigned long size;
    unsigned long int scanned = 0;
    int ret;

    int fd = get_test_file(_i, file, sizeof(file), &size);
    close(fd);

    cli_dbgmsg("scanning (scanfile_cb_allscan) %s\n", file);
    /* TODO: test callbacks */
    ret = cl_scanfile_callback(file, virpp, &scanned, g_engine, CL_SCAN_ALLMATCHES+CL_SCAN_STDOPT, NULL);
    cli_dbgmsg("scan end (scanfile_cb_allscan) %s\n", file);

    if (!FALSE_NEGATIVE) {
        fail_unless_fmt(ret == CL_VIRUS, "cl_scanfile_cb_allscan failed for %s: %s", file, cl_strerror(ret));
        virpp = (const char **)*virpp; /* allscan api hack */
        fail_unless_fmt(*virpp && !strcmp(*virpp, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", *virpp);
        free((void *)virpp);
    }
}
END_TEST

START_TEST (test_cl_scanfile_callback)
{
    const char *virname = NULL;
    char file[256];
    unsigned long size;
    unsigned long int scanned = 0;
    int ret;

    int fd = get_test_file(_i, file, sizeof(file), &size);
    close(fd);

    cli_dbgmsg("scanning (scanfile_cb) %s\n", file);
    /* TODO: test callbacks */
    ret = cl_scanfile_callback(file, &virname, &scanned, g_engine, CL_SCAN_STDOPT, NULL);
    cli_dbgmsg("scan end (scanfile_cb) %s\n", file);

    if (!FALSE_NEGATIVE) {
      fail_unless_fmt(ret == CL_VIRUS, "cl_scanfile_cb failed for %s: %s", file, cl_strerror(ret));
      fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", virname);
    }
}
Example #3
0
int scan_callback(STATBUF *sb, char *filename, const char *msg, enum cli_ftw_reason reason, struct cli_ftw_cbdata *data)
{
    struct scan_cb_data *scandata = data->data;
    const char *virname = NULL;
    int ret;
    int type = scandata->type;
    struct cb_context context;

    /* detect disconnected socket, 
     * this should NOT detect half-shutdown sockets (SHUT_WR) */
    if (send(scandata->conn->sd, &ret, 0, 0) == -1 && errno != EINTR) {
	logg("$Client disconnected while command was active!\n");
	thrmgr_group_terminate(scandata->conn->group);
	if (reason == visit_file)
	    free(filename);
	return CL_BREAK;
    }

    if (thrmgr_group_need_terminate(scandata->conn->group)) {
	logg("^Client disconnected while scanjob was active\n");
	if (reason == visit_file)
	    free(filename);
	return CL_BREAK;
    }
    scandata->total++;
    switch (reason) {
	case error_mem:
	    if (msg)
		logg("!Memory allocation failed during cli_ftw() on %s\n",
		     msg);
	    else
		logg("!Memory allocation failed during cli_ftw()\n");
	    scandata->errors++;
	    return CL_EMEM;
	case error_stat:
	    conn_reply_errno(scandata->conn, msg, "lstat() failed:");
	    logg("^lstat() failed on: %s\n", msg);
	    scandata->errors++;
	    return CL_SUCCESS;
	case warning_skipped_dir:
	    logg("^Directory recursion limit reached, skipping %s\n",
		     msg);
	    return CL_SUCCESS;
	case warning_skipped_link:
	    logg("$Skipping symlink: %s\n", msg);
	    return CL_SUCCESS;
	case warning_skipped_special:
	    if (msg == scandata->toplevel_path)
		conn_reply(scandata->conn, msg, "Not supported file type", "ERROR");
	    logg("*Not supported file type: %s\n", msg);
	    return CL_SUCCESS;
	case visit_directory_toplev:
	    return CL_SUCCESS;
	case visit_file:
	    break;
    }

    /* check whether the file is excluded */
#ifdef C_LINUX
    if(procdev && sb && (sb->st_dev == procdev)) {
	free(filename);
	return CL_SUCCESS;
    }
#endif

    if(sb && sb->st_size == 0) { /* empty file */
	if (msg == scandata->toplevel_path)
	    conn_reply_single(scandata->conn, filename, "Empty file");
	free(filename);
	return CL_SUCCESS;
    }

    if (type == TYPE_MULTISCAN) {
	client_conn_t *client_conn = (client_conn_t *) calloc(1, sizeof(struct client_conn_tag));
	if(client_conn) {
	    client_conn->scanfd = -1;
	    client_conn->sd = scandata->odesc;
	    client_conn->filename = filename;
	    client_conn->cmdtype = COMMAND_MULTISCANFILE;
	    client_conn->term = scandata->conn->term;
	    client_conn->options = scandata->options;
	    client_conn->opts = scandata->opts;
	    client_conn->group = scandata->group;
	    if(cl_engine_addref(scandata->engine)) {
		logg("!cl_engine_addref() failed\n");
		free(filename);
		free(client_conn);
		return CL_EMEM;
	    } else {
		client_conn->engine = scandata->engine;
		pthread_mutex_lock(&reload_mutex);
		client_conn->engine_timestamp = reloaded_time;
		pthread_mutex_unlock(&reload_mutex);
		if(!thrmgr_group_dispatch(scandata->thr_pool, scandata->group, client_conn, 1)) {
		    logg("!thread dispatch failed\n");
		    cl_engine_free(scandata->engine);
		    free(filename);
		    free(client_conn);
		    return CL_EMEM;
		}
	    }
	} else {
	    logg("!Can't allocate memory for client_conn\n");
	    scandata->errors++;
	    free(filename);
	    return CL_EMEM;
	}
	return CL_SUCCESS;
    }

    if (access(filename, R_OK)) {
	if (conn_reply(scandata->conn, filename, "Access denied.", "ERROR") == -1) {
	    free(filename);
	    return CL_ETIMEOUT;
	}
	logg("*Access denied: %s\n", filename);
	scandata->errors++;
	free(filename);
	return CL_SUCCESS;
    }

    thrmgr_setactivetask(filename, NULL);
    context.filename = filename;
    context.virsize = 0;
    context.scandata = scandata;
    ret = cl_scanfile_callback(filename, &virname, &scandata->scanned, scandata->engine, scandata->options, &context);
    thrmgr_setactivetask(NULL, NULL);

    if (thrmgr_group_need_terminate(scandata->conn->group)) {
	free(filename);
	logg("*Client disconnected while scanjob was active\n");
	return ret == CL_ETIMEOUT ? ret : CL_BREAK;
    }

    if ((ret == CL_VIRUS) && (virname == NULL)) {
        logg("*%s: reported CL_VIRUS but no virname returned!\n", filename);
        ret = CL_EMEM;
    }

    if (ret == CL_VIRUS) {
        scandata->infected++;

        if (scandata->options & CL_SCAN_ALLMATCHES) {
            if(optget(scandata->opts, "PreludeEnable")->enabled){
                prelude_logging(filename, virname, context.virhash, context.virsize);
            }
            virusaction(filename, virname, scandata->opts);
        } else {
            if (conn_reply_virus(scandata->conn, filename, virname) == -1) {
                free(filename);
                return CL_ETIMEOUT;
            }

            if(optget(scandata->opts, "PreludeEnable")->enabled){
                prelude_logging(filename, virname, context.virhash, context.virsize);
            }

            if(context.virsize && optget(scandata->opts, "ExtendedDetectionInfo")->enabled)
                logg("~%s: %s(%s:%llu) FOUND\n", filename, virname, context.virhash, context.virsize);
            else
                logg("~%s: %s FOUND\n", filename, virname);
            virusaction(filename, virname, scandata->opts);
        }
    } else if (ret != CL_CLEAN) {
	scandata->errors++;
	if (conn_reply(scandata->conn, filename, cl_strerror(ret), "ERROR") == -1) {
	    free(filename);
	    return CL_ETIMEOUT;
	}
	logg("~%s: %s ERROR\n", filename, cl_strerror(ret));
    } else if (logok) {
	logg("~%s: OK\n", filename);
    }

    free(filename);

    if(ret == CL_EMEM) /* stop scanning */
	return ret;

    if (type == TYPE_SCAN) {
	/* virus -> break */
	return ret;
    }

    /* keep scanning always */
    return CL_SUCCESS;
}
Example #4
0
static int scanstdin(const struct cl_engine *engine, const struct optstruct *opts, int options)
{
    int ret;
    unsigned int fsize = 0;
    const char *virname, *tmpdir;
    char *file, buff[FILEBUFF];
    size_t bread;
    FILE *fs;
    struct clamscan_cb_data data;

    if(optget(opts, "tempdir")->enabled) {
        tmpdir = optget(opts, "tempdir")->strarg;
    } else {
        /* check write access */
        tmpdir = cli_gettmpdir();
    }

    if(checkaccess(tmpdir, CLAMAVUSER, W_OK) != 1) {
        logg("!Can't write to temporary directory\n");
        return 2;
    }

    if(!(file = cli_gentemp(tmpdir))) {
        logg("!Can't generate tempfile name\n");
        return 2;
    }

    if(!(fs = fopen(file, "wb"))) {
        logg("!Can't open %s for writing\n", file);
        free(file);
        return 2;
    }

    while((bread = fread(buff, 1, FILEBUFF, stdin))) {
        fsize += bread;
        if(fwrite(buff, 1, bread, fs) < bread) {
            logg("!Can't write to %s\n", file);
            free(file);
            fclose(fs);
            return 2;
        }
    }

    fclose(fs);

    logg("*Checking %s\n", file);

    info.files++;
    info.rblocks += fsize / CL_COUNT_PRECISION;

    data.filename = "stdin";
    data.chain = NULL;
    if((ret = cl_scanfile_callback(file, &virname, &info.blocks, engine, options, &data)) == CL_VIRUS) {
        info.ifiles++;

        if(bell)
            fprintf(stderr, "\007");
    } else if(ret == CL_CLEAN) {
        if(!printinfected)
            mprintf("stdin: OK\n");
    } else {
        if(!printinfected)
            logg("stdin: %s ERROR\n", cl_strerror(ret));

        info.errors++;
    }

    unlink(file);
    free(file);
    return ret;
}
Example #5
0
static void *clamukolegacyth(void *arg)
{
	struct thrarg *tharg = (struct thrarg *) arg;
	sigset_t sigset;
	const char *virname;
        struct sigaction act;
	unsigned long mask = 0;
	const struct optstruct *pt;
	short int scan;
	int sizelimit = 0, extinfo;
	struct stat sb;
	struct cb_context context;


    clamuko_scanning = 0;

    /* ignore all signals except SIGUSR1 */
    sigfillset(&sigset);
    sigdelset(&sigset, SIGUSR1);
    /* The behavior of a process is undefined after it ignores a 
     * SIGFPE, SIGILL, SIGSEGV, or SIGBUS signal */
    sigdelset(&sigset, SIGFPE);
    sigdelset(&sigset, SIGILL);
    sigdelset(&sigset, SIGSEGV);
#ifdef SIGBUS    
    sigdelset(&sigset, SIGBUS);
#endif
    pthread_sigmask(SIG_SETMASK, &sigset, NULL);
    memset(&act, 0, sizeof(struct sigaction));
    act.sa_handler = clamuko_exit;
    sigfillset(&(act.sa_mask));
    sigaction(SIGUSR1, &act, NULL);
    sigaction(SIGSEGV, &act, NULL);

    /* register */
    if(dazukoRegister("ClamAV", "r+")) {
	logg("!Clamuko: Can't register with Dazuko\n");
	return NULL;
    } else
	logg("Clamuko: Correctly registered with Dazuko.\n");

    /* access mask */
    if(optget(tharg->opts, "ClamukoScanOnOpen")->enabled) {
	logg("Clamuko: Scan-on-open mode activated.\n");
	mask |= DAZUKO_ON_OPEN;
    }
    if(optget(tharg->opts, "ClamukoScanOnClose")->enabled) {
	logg("Clamuko: Scan-on-close mode activated.\n");
	mask |= DAZUKO_ON_CLOSE;
    }
    if(optget(tharg->opts, "ClamukoScanOnExec")->enabled) {
	logg("Clamuko: Scan-on-exec mode activated.\n");
	mask |= DAZUKO_ON_EXEC;
    }

    if(!mask) {
	logg("!Access mask is not configured properly.\n");
	dazukoUnregister();
	return NULL;
    }

    if(dazukoSetAccessMask(mask)) {
	logg("!Clamuko: Can't set access mask in Dazuko.\n");
	dazukoUnregister();
	return NULL;
    }

    if((pt = optget(tharg->opts, "ClamukoIncludePath"))->enabled) {
	while(pt) {
	    if((dazukoAddIncludePath(pt->strarg))) {
		logg("!Clamuko: Dazuko -> Can't include path %s\n", pt->strarg);
		dazukoUnregister();
		return NULL;
	    } else
		logg("Clamuko: Included path %s\n", pt->strarg);

	    pt = (struct optstruct *) pt->nextarg;
	}
    } else {
	logg("!Clamuko: please include at least one path.\n");
	dazukoUnregister();
	return NULL;
    }

    if((pt = optget(tharg->opts, "ClamukoExcludePath"))->enabled) {
	while(pt) {
	    if((dazukoAddExcludePath(pt->strarg))) {
		logg("!Clamuko: Dazuko -> Can't exclude path %s\n", pt->strarg);
		dazukoUnregister();
		return NULL;
	    } else
		logg("Clamuko: Excluded path %s\n", pt->strarg);

	    pt = (struct optstruct *) pt->nextarg;
	}
    }

    sizelimit = optget(tharg->opts, "ClamukoMaxFileSize")->numarg;
    if(sizelimit)
	logg("Clamuko: Max file size limited to %d bytes.\n", sizelimit);
    else
	logg("Clamuko: File size limit disabled.\n");

    extinfo = optget(tharg->opts, "ExtendedDetectionInfo")->enabled;

    while(1) {

	if(dazukoGetAccess(&acc) == 0) {
	    clamuko_scanning = 1;
	    scan = 1;

	    if(sizelimit) {
		stat(acc->filename, &sb);
		if(sb.st_size > sizelimit) {
		    scan = 0;
		    logg("*Clamuko: %s skipped (too big)\n", acc->filename);
		}
	    }

	    if(clamuko_checkowner(acc->pid, tharg->opts)) {
		scan = 0;
		logg("*Clamuko: %s skipped (excluded UID)\n", acc->filename);
	    }

	    context.filename = acc->filename;
	    context.virsize = 0;
	    if(scan && cl_scanfile_callback(acc->filename, &virname, NULL, tharg->engine, tharg->options, &context) == CL_VIRUS) {
		if(context.virsize)
		    detstats_add(virname, acc->filename, context.virsize, context.virhash);
		if(extinfo && context.virsize)
		    logg("Clamuko: %s: %s(%s:%llu) FOUND\n", acc->filename, virname, context.virhash, context.virsize);
		else
		    logg("Clamuko: %s: %s FOUND\n", acc->filename, virname);
		virusaction(acc->filename, virname, tharg->opts);
		acc->deny = 1;
	    } else
		acc->deny = 0;

	    if(dazukoReturnAccess(&acc)) {
		logg("!Can't return access to Dazuko.\n");
		logg("Clamuko stopped.\n");
		dazukoUnregister();
		clamuko_scanning = 0;
		return NULL;
	    }

	    clamuko_scanning = 0;
	}
    }

    /* can't be ;) */
    return NULL;
}