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) {
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); }
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; }
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); }
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); }
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); }
const oval_probe_meta_t * const oval_probe_meta_get(void) { return (const oval_probe_meta_t * const)OSCAP_GSYM(__probe_meta); }
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); }
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); }