Beispiel #1
0
static int probe_opthandler_offlinemode(int option, int op, va_list args)
{
	if (op == PROBE_OPTION_SET) {
		probe_offline_flags o_offline_mode;
		int o_cobjflag = OSCAP_GSYM(offline_mode_cobjflag);

		o_offline_mode = va_arg(args, int);
		if (o_offline_mode != PROBE_OFFLINE_ALL) {
			/*
			 * If the probe doesn't support offline mode, then probe_main()
			 * won't be called in offline modee and a collected object with
			 * the following flag will be generated for all queries.
			 *
			 * We have hardcoded not_collected here as the best fit for majority
			 * of offline use cases. The test result will get the unknown result
			 * which is pretty descriptive of the state.
			 *
			 * Other option would be to return not applicable. That would, however,
			 * make the test result not_applicable as well. Which in turn may hide
			 * underlying problems.
			 */
			o_cobjflag = SYSCHAR_FLAG_NOT_COLLECTED;
		}
		OSCAP_GSYM(offline_mode_supported) = o_offline_mode;
		OSCAP_GSYM(offline_mode_cobjflag) = o_cobjflag;
	} else if (op == PROBE_OPTION_GET) {
Beispiel #2
0
static int probe_opthandler_varref(int option, int op, va_list args)
{
	bool  o_switch;
	char *o_name;
	char *o_temp;

	if (op == PROBE_OPTION_GET)
		return -1;

	o_switch = va_arg(args, int);
	o_name   = va_arg(args, char *);

	if (o_name == NULL) {
		/* switch varref handling on/off globally */
		OSCAP_GSYM(varref_handling) = o_switch;
		return (0);
	}

	o_temp = oscap_bfind (OSCAP_GSYM(no_varref_ents), OSCAP_GSYM(no_varref_ents_cnt),
			      sizeof(char *), o_name, (int(*)(void *, void *)) &probe_optecmp);

	if (o_temp != NULL)
		return (0);

	OSCAP_GSYM(no_varref_ents) = oscap_realloc(OSCAP_GSYM(no_varref_ents),
						   sizeof (char *) * ++OSCAP_GSYM(no_varref_ents_cnt));
	OSCAP_GSYM(no_varref_ents)[OSCAP_GSYM(no_varref_ents_cnt) - 1] = strdup(o_name);

	qsort(OSCAP_GSYM(no_varref_ents), OSCAP_GSYM(no_varref_ents_cnt),
              sizeof (char *), (int(*)(const void *, const void *))&probe_optecmp);

	return (0);
}
/**
 * Initialize element name cache and register an exit hook.
 */
static void ncache_libinit(void)
{
        if (OSCAP_GSYM(ncache) == NULL) {
                OSCAP_GSYM(ncache) = probe_ncache_new();
                atexit(ncache_libfree);
        }
}
oval_probe_session_t *oval_probe_session_new(struct oval_syschar_model *model)
{
        oval_probe_session_t *sess;
        void *handler_arg;
        register size_t i;

        sess = oscap_talloc(oval_probe_session_t);
        sess->ph = oval_phtbl_new();
        sess->sys_model = model;
        sess->flg = 0;
        sess->pext = oval_pext_new();
        sess->pext->model    = &sess->sys_model;
        sess->pext->sess_ptr = sess;

        __init_once();

        dD("__probe_meta_count = %zu", OSCAP_GSYM(__probe_meta_count));

        for (i = 0; i < OSCAP_GSYM(__probe_meta_count); ++i) {
                handler_arg = NULL;

                if (OSCAP_GSYM(__probe_meta)[i].flags & OVAL_PROBEMETA_EXTERNAL)
                        handler_arg = sess->pext;

                oval_probe_handler_set(sess->ph,
				       OSCAP_GSYM(__probe_meta)[i].otype,
				       OSCAP_GSYM(__probe_meta)[i].handler, handler_arg);
        }

        oval_probe_handler_set(sess->ph, OVAL_SUBTYPE_ALL, oval_probe_ext_handler, sess->pext); /* special case for reset */
        return(sess);
}
Beispiel #5
0
void oval_probe_meta_list(FILE *output, int flags)
{
	register size_t i;
	const char *probe_dir;
	oval_probe_meta_t *meta = OSCAP_GSYM(__probe_meta);
	size_t probe_dirlen;
	char probe_path[PATH_MAX+1];

	if (output == NULL)
		output = stdout;

	probe_dir = oval_probe_ext_getdir();
	assume_d(probe_dir != NULL, /* void */);
	probe_dirlen = strlen(probe_dir);
	assume_r(probe_dirlen + 1 <= PATH_MAX, /* void */);

	for (i = 0; i < OSCAP_GSYM(__probe_meta_count); ++i) {
		if (meta[i].flags & OVAL_PROBEMETA_EXTERNAL) {
			strncpy(probe_path, probe_dir, PATH_MAX);
			probe_path[probe_dirlen] = '/';
			probe_path[probe_dirlen+1] = '\0';
			strncat(probe_path, meta[i].pname, PATH_MAX - strlen(probe_dir) - 1);

			if (flags & OVAL_PROBEMETA_LIST_DYNAMIC) {
				dI("Checking access to \"%s\"\n", probe_path);
				if (access(probe_path, X_OK) != 0) {
					dW("access: errno=%d, %s\n", errno, strerror(errno));
					continue;
				}
			}
		}

		fprintf(output, "%-28s %-28s", meta[i].stype, meta[i].pname);

		if (flags & OVAL_PROBEMETA_LIST_VERBOSE) {
			if (meta[i].flags & OVAL_PROBEMETA_EXTERNAL) {
				fprintf(output, " %-5u %s\n", meta[i].otype, probe_path);
			} else {
				fprintf(output, " %-5u\n", meta[i].otype);
			}
		} else
			fprintf(output, "\n");
	}

	return;
}
Beispiel #6
0
oval_subtype_t oval_str_to_subtype(const char *str)
{
        oval_subtypedsc_t *d;

        __init_once();

        d = oscap_bfind(OSCAP_GSYM(__n2s_tbl), __n2s_tbl_count, sizeof(oval_subtypedsc_t), (void *)str,
                        (int(*)(void *, void *))__n2s_tbl_cmp);

        return (d == NULL ? OVAL_SUBTYPE_UNKNOWN : d->type);
}
Beispiel #7
0
const char *oval_subtype_to_str(oval_subtype_t subtype)
{
        oval_subtypedsc_t *d;

        __init_once();

        d = oscap_bfind(OSCAP_GSYM(__s2n_tbl), __s2n_tbl_count, sizeof(oval_subtypedsc_t), &subtype,
                        (int(*)(void *, void *))__s2n_tbl_cmp);

        return (d == NULL ? NULL : d->name);
}
Beispiel #8
0
void *probe_init (void)
{
#ifdef RPM46_FOUND
	rpmlogSetCallback(rpmErrorCb, NULL);
#endif
        if (rpmReadConfigFiles ((const char *)NULL, (const char *)NULL) != 0) {
                dI("rpmReadConfigFiles failed: %u, %s.", errno, strerror (errno));
                return (NULL);
        }

        g_rpm.rpmts = rpmtsCreate();

        pthread_mutex_init(&(g_rpm.mutex), NULL);

	if (OSCAP_GSYM(offline_mode) & PROBE_OFFLINE_OWN) {
		const char* root = getenv("OSCAP_PROBE_ROOT");
		rpmtsSetRootDir(g_rpm.rpmts, root);
	}

        return ((void *)&g_rpm);
}
Beispiel #9
0
const oval_probe_meta_t * const oval_probe_meta_get(void)
{
    return (const oval_probe_meta_t * const)OSCAP_GSYM(__probe_meta);
}
Beispiel #10
0
void oval_probe_tblinit(void)
{
        register size_t i;

        for(i = 0; i < OSCAP_GSYM(__probe_meta_count); ++i) {
                OSCAP_GSYM(__s2n_tbl)[i].type = OSCAP_GSYM(__probe_meta)[i].otype;
                OSCAP_GSYM(__n2s_tbl)[i].type = OSCAP_GSYM(__probe_meta)[i].otype;
                OSCAP_GSYM(__s2n_tbl)[i].name = OSCAP_GSYM(__probe_meta)[i].stype;
                OSCAP_GSYM(__n2s_tbl)[i].name = OSCAP_GSYM(__probe_meta)[i].stype;
        }

        qsort(OSCAP_GSYM(__s2n_tbl), OSCAP_GSYM(__probe_meta_count), sizeof (oval_subtypedsc_t),
              (int(*)(const void *, const void *))__s2n_tbl_sortcmp);

        qsort(OSCAP_GSYM(__n2s_tbl), OSCAP_GSYM(__probe_meta_count), sizeof (oval_subtypedsc_t),
              (int(*)(const void *, const void *))__n2s_tbl_sortcmp);
}
int probe_main(probe_ctx *ctx, void *arg)
{
	SEXP_t *path_ent, *file_ent, *inst_ent, *bh_ent, *patt_ent, *filepath_ent, *probe_in;
        SEXP_t *r0;
	/* char *i_val, *m_val, *s_val; */
	bool val;
	struct pfdata pfd;
	int ret = 0;
	int errorffset = -1;
	const char *error;
	OVAL_FTS    *ofts;
	OVAL_FTSENT *ofts_ent;
	char path_with_root[PATH_MAX + 1];
	unsigned int root_len = 0;

        (void)arg;

	memset(&pfd, 0, sizeof(pfd));

        probe_in = probe_ctx_getobject(ctx);

	over = probe_obj_get_platform_schema_version(probe_in);
        path_ent = probe_obj_getent(probe_in, "path",     1);
        file_ent = probe_obj_getent(probe_in, "filename", 1);
        inst_ent = probe_obj_getent(probe_in, "instance", 1);
        patt_ent = probe_obj_getent(probe_in, "pattern",  1);
        filepath_ent = probe_obj_getent(probe_in, "filepath",  1);
	bh_ent = probe_obj_getent(probe_in, "behaviors", 1);

        /* we want (path+filename or filepath) + instance + pattern*/
        if ( ((path_ent == NULL || file_ent == NULL) && filepath_ent==NULL) || 
             inst_ent==NULL || 
             patt_ent==NULL) {
                SEXP_free (patt_ent);
		ret = PROBE_ENOELM;
		goto cleanup;
        }

	/* get pattern from SEXP */
        SEXP_t *ent_val;
        ent_val = probe_ent_getval(patt_ent);
	pfd.pattern = SEXP_string_cstr(ent_val);
	assume_d(pfd.pattern != NULL, -1);
        SEXP_free(patt_ent);
        SEXP_free(ent_val);

        /* wtf?
	i_val = s_val = "0";
	m_val = "1";
        */

	/* reset filebehavior attributes if 'filepath' entity is used */
	if (filepath_ent != NULL && bh_ent != NULL) {
		SEXP_t *r1, *r2, *r3;
		r1 = r2 = r3 = NULL;
		if (probe_ent_attrexists(bh_ent, "ignore_case")) {
			r1 = probe_ent_getattrval(bh_ent, "ignore_case");
		}
		if (probe_ent_attrexists(bh_ent, "multiline")) {
			r2 = probe_ent_getattrval(bh_ent, "multiline");
		}
		if (probe_ent_attrexists(bh_ent, "singleline")) {
			r3 = probe_ent_getattrval(bh_ent, "singleline");
		}
		r0 = SEXP_list_new(NULL);
		SEXP_free(bh_ent);
		bh_ent = probe_ent_creat1("behaviors", r0, NULL);
		SEXP_free(r0);
		if (r1) {
			probe_ent_attr_add(bh_ent, "ignore_case", r1);
			SEXP_free(r1);
		}
		if (r2) {
			probe_ent_attr_add(bh_ent, "multiline", r2);
			SEXP_free(r2);
		}
		if (r3) {
			probe_ent_attr_add(bh_ent, "singleline", r3);
			SEXP_free(r3);
		}
	}

	probe_tfc54behaviors_canonicalize(&bh_ent);

	pfd.instance_ent = inst_ent;
        pfd.ctx          = ctx;
	pfd.re_opts = PCRE_UTF8;
	r0 = probe_ent_getattrval(bh_ent, "ignore_case");
	if (r0) {
		val = SEXP_string_getb(r0);
		SEXP_free(r0);
		if (val)
			pfd.re_opts |= PCRE_CASELESS;
	}
	r0 = probe_ent_getattrval(bh_ent, "multiline");
	if (r0) {
		val = SEXP_string_getb(r0);
		SEXP_free(r0);
		if (val)
			pfd.re_opts |= PCRE_MULTILINE;
	}
	r0 = probe_ent_getattrval(bh_ent, "singleline");
	if (r0) {
		val = SEXP_string_getb(r0);
		SEXP_free(r0);
		if (val)
			pfd.re_opts |= PCRE_DOTALL;
	}

	pfd.compiled_regex = pcre_compile(pfd.pattern, pfd.re_opts, &error,
					  &errorffset, NULL);
	if (pfd.compiled_regex == NULL) {
		SEXP_t *msg;

		msg = probe_msg_creatf(OVAL_MESSAGE_LEVEL_ERROR, "pcre_compile() '%s' %s.", pfd.pattern, error);
		probe_cobj_add_msg(probe_ctx_getresult(pfd.ctx), msg);
		SEXP_free(msg);
		probe_cobj_set_flag(probe_ctx_getresult(pfd.ctx), SYSCHAR_FLAG_ERROR);
		goto cleanup;
	}

	path_with_root[PATH_MAX] = '\0';
	if (OSCAP_GSYM(offline_mode) & PROBE_OFFLINE_OWN) {
		strncpy(path_with_root, getenv("OSCAP_PROBE_ROOT"), PATH_MAX);
		root_len = strlen(path_with_root);

		if (path_with_root[root_len - 1] == FILE_SEPARATOR)
			--root_len;
	}

	if ((ofts = oval_fts_open(path_ent, file_ent, filepath_ent, bh_ent, probe_ctx_getresult(ctx))) != NULL) {
		while ((ofts_ent = oval_fts_read(ofts)) != NULL) {
			if (ofts_ent->fts_info == FTS_F
			    || ofts_ent->fts_info == FTS_SL) {
				strncpy(path_with_root + root_len, ofts_ent->path, PATH_MAX - root_len);
				// todo: handle return code
				process_file(path_with_root, ofts_ent->file, &pfd);
			}
			oval_ftsent_free(ofts_ent);
		}

		oval_fts_close(ofts);
	}

 cleanup:
        SEXP_free(file_ent);
        SEXP_free(path_ent);
        SEXP_free(inst_ent);
        SEXP_free(bh_ent);
        SEXP_free(filepath_ent);
	if (pfd.pattern != NULL)
		free(pfd.pattern);
	if (pfd.compiled_regex != NULL)
		pcre_free(pfd.compiled_regex);
	return ret;
}
/**
 * Entity name cache exit hook. This hook is registered using
 * atexit(3) during initialization and ensures that the element
 * name cache is freed before exit.
 */
static void ncache_libfree(void)
{
        probe_ncache_free(OSCAP_GSYM(ncache));
}
void *probe_signal_handler(void *arg)
{
        probe_t  *probe = (probe_t *)arg;
	siginfo_t siinf;
	sigset_t  siset;

#if defined(HAVE_PTHREAD_SETNAME_NP)
# if defined(__APPLE__)
	pthread_setname_np("signal_handler");
# else
	pthread_setname_np(pthread_self(), "signal_handler");
# endif
#endif

	sigemptyset(&siset);
	sigaddset(&siset, SIGHUP);
	sigaddset(&siset, SIGUSR1);
	sigaddset(&siset, SIGUSR2);
	sigaddset(&siset, SIGINT);
	sigaddset(&siset, SIGTERM);
	sigaddset(&siset, SIGQUIT);
        sigaddset(&siset, SIGPIPE);

#if defined(__linux__)
        if (prctl(PR_SET_PDEATHSIG, SIGTERM) != 0)
                dW("prctl(PR_SET_PDEATHSIG, SIGTERM) failed");
#endif
       
	dD("Signal handler ready");
	switch (errno = pthread_barrier_wait(&OSCAP_GSYM(th_barrier)))
	{
	case 0:
	case PTHREAD_BARRIER_SERIAL_THREAD:
		break;
	default:
		dE("pthread_barrier_wait: %d, %s.", errno, strerror(errno));
		return (NULL);
	}

	while (sigwaitinfo(&siset, &siinf) != -1) {

		dD("Received signal %d from %u (%s)",
		   siinf.si_signo, (unsigned int)siinf.si_pid,
		   getppid() == siinf.si_pid ? "parent" : "not my parent");

#if defined(PROBE_SIGNAL_PARENTONLY)
		/* Listen only to signals sent from the parent process */
		if (getppid() != siinf.si_pid)
			continue;
#endif

		switch(siinf.si_signo) {
		case SIGUSR1:/* probe abort */
                        probe->probe_exitcode = ECONNABORTED;
			/* FALLTHROUGH */
                case SIGINT:
                case SIGTERM:
                case SIGQUIT:
                case SIGPIPE:
		{
			__thr_collection coll;

			coll.thr = NULL;
			coll.cnt = 0;

                        pthread_cancel(probe->th_input);

			/* collect IDs and cancel threads */
			rbt_walk_inorder2(probe->workers, __abort_cb, &coll, 0);

			/*
			 * Wait till all threads are canceled (they may temporarily disable
			 * cancelability), but at most 60 seconds per thread.
			 */
			for (; coll.cnt > 0; --coll.cnt) {
				probe_worker_t *thr = coll.thr[coll.cnt - 1];
#if defined(HAVE_PTHREAD_TIMEDJOIN_NP) && defined(HAVE_CLOCK_GETTIME)
				struct timespec j_tm;

				if (clock_gettime(CLOCK_REALTIME, &j_tm) == -1) {
					dE("clock_gettime(CLOCK_REALTIME): %d, %s.", errno, strerror(errno));
					continue;
				}

				j_tm.tv_sec += 60;

				if ((errno = pthread_timedjoin_np(thr->tid, NULL, &j_tm)) != 0) {
					dE("[%llu] pthread_timedjoin_np: %d, %s.", (uint64_t)thr->sid, errno, strerror(errno));
					/*
					 * Memory will be leaked here by continuing to the next thread. However, we are in the
					 * process of shutting down the whole probe. We're just nice and gave the probe_main()
					 * thread a chance to finish it's critical section which shouldn't take that long...
					 */
					continue;
				}
#else
				if ((errno = pthread_join(thr->tid, NULL)) != 0) {
					dE("pthread_join: %d, %s.", errno, strerror(errno));
					continue;
				}
#endif
				SEAP_msg_free(coll.thr[coll.cnt - 1]->msg);
                                oscap_free(coll.thr[coll.cnt - 1]);
			}

			oscap_free(coll.thr);
			goto exitloop;
		}
                case SIGUSR2:
                case SIGHUP:
                        /* ignore */
                        break;
                }
	}
exitloop:
	return (NULL);
}
Beispiel #14
0
static void *probe_icache_worker(void *arg)
{
        probe_icache_t *cache = (probe_icache_t *)(arg);
        probe_iqpair_t *pair, pair_mem;
        SEXP_ID_t       item_ID;

        assume_d(cache != NULL, NULL);

	pthread_setname_np(pthread_self(), "icache_worker");

        if (pthread_mutex_lock(&cache->queue_mutex) != 0) {
                dE("An error ocured while locking the queue mutex: %u, %s",
                   errno, strerror(errno));
                return (NULL);
        }

	pair = &pair_mem;
        dD("icache worker ready");

        switch (errno = pthread_barrier_wait(&OSCAP_GSYM(th_barrier)))
        {
        case 0:
        case PTHREAD_BARRIER_SERIAL_THREAD:
	        break;
        default:
	        dE("pthread_barrier_wait: %d, %s.",
	           errno, strerror(errno));
	        pthread_mutex_unlock(&cache->queue_mutex);
	        return (NULL);
        }

        while(pthread_cond_wait(&cache->queue_notempty, &cache->queue_mutex) == 0) {
                assume_d(cache->queue_cnt > 0, NULL);
        next:
                dD("Extracting item from the cache queue: cnt=%"PRIu16", beg=%"PRIu16"", cache->queue_cnt, cache->queue_beg);
                /*
                 * Extract an item from the queue and update queue beg, end & cnt
                 */
                pair_mem = cache->queue[cache->queue_beg];
#ifndef NDEBUG
		memset(cache->queue + cache->queue_beg, 0, sizeof(probe_iqpair_t));
#endif
                --cache->queue_cnt;
		++cache->queue_beg;

		if (cache->queue_beg == cache->queue_max)
			cache->queue_beg = 0;

		assume_d(cache->queue_cnt == 0 ?
			 cache->queue_end == cache->queue_beg :
			 cache->queue_end != cache->queue_beg, NULL);

                /*
                 * Release the mutex
                 */
                if (pthread_mutex_unlock(&cache->queue_mutex) != 0) {
                        dE("An error ocured while unlocking the queue mutex: %u, %s",
                           errno, strerror(errno));
                        abort();
                }

                dD("Signaling `notfull'");

                if (pthread_cond_signal(&cache->queue_notfull) != 0) {
                        dE("An error ocured while signaling the `notfull' condition: %u, %s",
                           errno, strerror(errno));
                        abort();
                }

                if (pair->cobj == NULL) {
                        /*
                         * Handle NOP case (synchronization)
                         */
                        assume_d(pair->p.cond != NULL, NULL);

                        dD("Handling NOP");

                        if (pthread_cond_signal(pair->p.cond) != 0) {
                                dE("An error ocured while signaling NOP condition: %u, %s",
                                   errno, strerror(errno));
                                abort();
                        }
                } else {
                        probe_citem_t *cached = NULL;

                        dD("Handling cache request");

                        /*
                         * Compute item ID
                         */
                        item_ID = SEXP_ID_v(pair->p.item);
                        dD("item ID=%"PRIu64"", item_ID);

                        /*
                         * Perform cache lookup
                         */
                        if (rbt_i64_get(cache->tree, (int64_t)item_ID, (void *)&cached) == 0) {
                                register uint16_t i;
				SEXP_t   rest1, rest2;
                                /*
                                 * Maybe a cache HIT
                                 */
                                dD("cache HIT #1");

                                for (i = 0; i < cached->count; ++i) {
                                        if (SEXP_deepcmp(SEXP_list_rest_r(&rest1, pair->p.item),
							 SEXP_list_rest_r(&rest2, cached->item[i])))
					{
						SEXP_free_r(&rest1);
						SEXP_free_r(&rest2);
                                                break;
					}

					SEXP_free_r(&rest1);
					SEXP_free_r(&rest2);
                                }

                                if (i == cached->count) {
                                        /*
                                         * Cache MISS
                                         */
                                        dD("cache MISS");

                                        cached->item = oscap_realloc(cached->item, sizeof(SEXP_t *) * ++cached->count);
                                        cached->item[cached->count - 1] = pair->p.item;

                                        /* Assign an unique item ID */
                                        probe_icache_item_setID(pair->p.item, item_ID);
                                } else {
                                        /*
                                         * Cache HIT
                                         */
                                        dD("cache HIT #2 -> real HIT");
                                        SEXP_free(pair->p.item);
                                        pair->p.item = cached->item[i];
                                }
                        } else {
                                /*
                                 * Cache MISS
                                 */
                                dD("cache MISS");
                                cached = oscap_talloc(probe_citem_t);
                                cached->item = oscap_talloc(SEXP_t *);
                                cached->item[0] = pair->p.item;
                                cached->count = 1;

                                /* Assign an unique item ID */
                                probe_icache_item_setID(pair->p.item, item_ID);

                                if (rbt_i64_add(cache->tree, (int64_t)item_ID, (void *)cached, NULL) != 0) {
                                        dE("Can't add item (k=%"PRIi64" to the cache (%p)", (int64_t)item_ID, cache->tree);

                                        oscap_free(cached->item);
                                        oscap_free(cached);

                                        /* now what? */
                                        abort();
                                }
                        }

                        if (probe_cobj_add_item(pair->cobj, pair->p.item) != 0) {
                            dW("An error ocured while adding the item to the collected object");
                        }
                }

                if (pthread_mutex_lock(&cache->queue_mutex) != 0) {
                        dE("An error ocured while re-locking the queue mutex: %u, %s",
                           errno, strerror(errno));
                        abort();
                }

                if (cache->queue_cnt > 0)
                        goto next;
        }

        return (NULL);
}