summaryrefslogtreecommitdiffstats
path: root/seaudit/preferences.c
diff options
context:
space:
mode:
Diffstat (limited to 'seaudit/preferences.c')
-rw-r--r--seaudit/preferences.c585
1 files changed, 585 insertions, 0 deletions
diff --git a/seaudit/preferences.c b/seaudit/preferences.c
new file mode 100644
index 0000000..5e65385
--- /dev/null
+++ b/seaudit/preferences.c
@@ -0,0 +1,585 @@
+/**
+ * @file
+ * Implementation of the storage class preferences_t.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author Jeremy Solt jsolt@tresys.com
+ *
+ * Copyright (C) 2003-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <config.h>
+
+#include "preferences.h"
+
+#include <apol/util.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+/** default frequency, in milliseconds, to poll log file for changes */
+#define DEFAULT_LOG_UPDATE_INTERVAL 1000
+
+/** maximum number of recent log files and recent policy files to remember */
+#define MAX_RECENT_ENTRIES 5
+
+/** name of the user's seaudit personal preferences file */
+#define USER_SEAUDIT_CONF ".seaudit"
+
+/** name of the system seaudit preference file */
+#define SYSTEM_SEAUDIT_CONF "dot_seaudit"
+
+struct visible_field
+{
+ preference_field_e id;
+ const char *field;
+ int visible;
+};
+
+static const struct visible_field default_visible_fields[] = {
+ {HOST_FIELD, "host_field", 1},
+ {MESSAGE_FIELD, "msg_field", 1},
+ {DATE_FIELD, "date_field", 1},
+ {SUSER_FIELD, "src_usr_field", 0},
+ {SROLE_FIELD, "src_role_field", 0},
+ {STYPE_FIELD, "src_type_field", 1},
+ {SMLS_LVL_FIELD, "src_mls_lvl_field", 0},
+ {SMLS_CLR_FIELD, "src_mls_clr_field", 0},
+ {TUSER_FIELD, "tgt_usr_field", 0},
+ {TROLE_FIELD, "tgt_role_field", 0},
+ {TTYPE_FIELD, "tgt_type_field", 1},
+ {TMLS_LVL_FIELD, "tgt_mls_lvl_field", 0},
+ {TMLS_CLR_FIELD, "tgt_mls_clr_field", 0},
+ {OBJCLASS_FIELD, "obj_class_field", 1},
+ {PERM_FIELD, "perm_field", 1},
+ {EXECUTABLE_FIELD, "exe_field", 1},
+ {COMMAND_FIELD, "comm_field", 1},
+ {NAME_FIELD, "name_field", 0},
+ {PID_FIELD, "pid_field", 0},
+ {INODE_FIELD, "inode_field", 0},
+ {PATH_FIELD, "path_field", 0},
+ {OTHER_FIELD, "other_field", 1}
+};
+
+static const size_t num_visible_fields = sizeof(default_visible_fields) / sizeof(default_visible_fields[0]);
+
+struct preferences
+{
+ /** path to default system log file */
+ char *log;
+ /** path to default policy */
+ apol_policy_path_t *policy;
+ /** default path when writing reports */
+ char *report;
+ /** default path to the stylesheet, used during report writing */
+ char *stylesheet;
+ /** vector of paths (strings) to recently opened log files */
+ apol_vector_t *recent_log_files;
+ /** vector of apol_policy_path_t objects to recently opened
+ policies */
+ apol_vector_t *recent_policy_files;
+ /** non-zero if seaudit should poll the log file for changes */
+ int real_time_log;
+ /** frequency, in milliesconds, to poll log file */
+ int real_time_interval;
+ struct visible_field *fields;
+};
+
+void preferences_apol_policy_path_free(void *elem)
+{
+ apol_policy_path_t *path = elem;
+ apol_policy_path_destroy(&path);
+}
+
+/**
+ * Parse the old-style recent policies list (a ':' separated list of
+ * paths) into the recent_policy_files field.
+ */
+static int preferences_parse_old_recent_files(preferences_t * prefs, const char *s)
+{
+ apol_vector_t *v = NULL;
+ size_t i;
+ char *base;
+ apol_policy_path_t *path;
+ int error = 0;
+
+ if ((v = apol_str_split(s, ":")) == NULL) {
+ error = errno;
+ goto cleanup;
+ }
+ for (i = 0; i < apol_vector_get_size(v); i++) {
+ base = apol_vector_get_element(v, i);
+ if ((path = apol_policy_path_create(APOL_POLICY_PATH_TYPE_MONOLITHIC, base, NULL)) == NULL ||
+ apol_vector_append(prefs->recent_policy_files, path) < 0) {
+ error = errno;
+ apol_policy_path_destroy(&path);
+ goto cleanup;
+ }
+ }
+
+ cleanup:
+ apol_vector_destroy(&v);
+ if (error != 0) {
+ errno = error;
+ return -1;
+ }
+ return 0;
+}
+
+/**
+ * Parse the new recent policy files, which now spans across multiple
+ * lines.
+ */
+static int preferences_parse_new_recent_files(preferences_t * prefs, FILE * f, int num_files)
+{
+ int count;
+ for (count = 0; count < num_files; count++) {
+ char *var_name, *value = NULL;
+ apol_policy_path_t *p = NULL;
+ if (asprintf(&var_name, "RECENT_POLICY_PATH_%d", count) < 0) {
+ return -1;
+ }
+ value = apol_config_get_var(var_name, f);
+ free(var_name);
+ if (value == NULL ||
+ (p = apol_policy_path_create_from_string(value)) == NULL ||
+ apol_vector_append(prefs->recent_policy_files, p) < 0) {
+ free(value);
+ apol_policy_path_destroy(&p);
+ return -1;
+ }
+ free(value);
+ }
+ return 0;
+}
+
+preferences_t *preferences_create(void)
+{
+ preferences_t *prefs = NULL;
+ FILE *file = NULL;
+ char *path = NULL, *value;
+ apol_vector_t *v = NULL;
+ size_t i, j;
+ int error = 0;
+
+ if ((prefs = calloc(1, sizeof(*prefs))) == NULL ||
+ (prefs->log = strdup("")) == NULL ||
+ (prefs->report = strdup("")) == NULL ||
+ (prefs->stylesheet = strdup("")) == NULL ||
+ (prefs->recent_log_files = apol_vector_create(free)) == NULL ||
+ (prefs->recent_policy_files = apol_vector_create(preferences_apol_policy_path_free)) == NULL ||
+ (prefs->fields = calloc(num_visible_fields, sizeof(struct visible_field))) == NULL) {
+ error = errno;
+ goto cleanup;
+ }
+ prefs->real_time_interval = DEFAULT_LOG_UPDATE_INTERVAL;
+ memcpy(prefs->fields, default_visible_fields, num_visible_fields * sizeof(struct visible_field));
+ path = apol_file_find_user_config(USER_SEAUDIT_CONF);
+ if (!path) {
+ if ((path = apol_file_find_path(SYSTEM_SEAUDIT_CONF)) == NULL) {
+ return prefs;
+ }
+ }
+ if ((file = fopen(path, "r")) == NULL) {
+ error = errno;
+ goto cleanup;
+ }
+ if ((value = apol_config_get_var("DEFAULT_LOG_FILE", file)) != NULL) {
+ free(prefs->log);
+ prefs->log = value;
+ }
+ if ((value = apol_config_get_var("DEFAULT_POLICY_FILE", file)) != NULL) {
+ apol_policy_path_destroy(&prefs->policy);
+ if (apol_policy_path_create(APOL_POLICY_PATH_TYPE_MONOLITHIC, value, NULL) == NULL) {
+ error = errno;
+ free(value);
+ goto cleanup;
+ }
+ free(value);
+ }
+ if ((value = apol_config_get_var("DEFAULT_POLICY_PATH", file)) != NULL) {
+ apol_policy_path_destroy(&prefs->policy);
+ if ((prefs->policy = apol_policy_path_create_from_string(value)) == NULL) {
+ error = errno;
+ free(value);
+ goto cleanup;
+ }
+ free(value);
+ }
+ if ((value = apol_config_get_var("DEFAULT_REPORT_CONFIG_FILE", file)) != NULL) {
+ free(prefs->report);
+ prefs->report = value;
+ }
+ if ((value = apol_config_get_var("DEFAULT_REPORT_CSS_FILE", file)) != NULL) {
+ free(prefs->stylesheet);
+ prefs->stylesheet = value;
+ }
+ if ((value = apol_config_get_var("RECENT_LOG_FILES", file)) == NULL || (v = apol_str_split(value, ":")) == NULL) {
+ error = errno;
+ free(value);
+ goto cleanup;
+ }
+ free(value);
+ apol_vector_destroy(&prefs->recent_log_files);
+ prefs->recent_log_files = v;
+
+ /* test if there exists the new recent list that contains
+ * module filenames */
+ if ((value = apol_config_get_var("RECENT_POLICY_PATH_FILES", file)) != NULL) {
+ if (preferences_parse_new_recent_files(prefs, file, atoi(value)) < 0) {
+ error = errno;
+ free(value);
+ goto cleanup;
+ }
+ } else {
+ /* use older style that could only handle monolithic policies */
+ if ((value = apol_config_get_var("RECENT_POLICY_FILES", file)) == NULL
+ || preferences_parse_old_recent_files(prefs, value) < 0) {
+ error = errno;
+ free(value);
+ goto cleanup;
+ }
+ }
+ free(value);
+
+ if ((value = apol_config_get_var("LOG_COLUMNS_HIDDEN", file)) == NULL || (v = apol_str_split(value, ":")) == NULL) {
+ error = errno;
+ goto cleanup;
+ }
+ for (j = 0; j < num_visible_fields; j++) {
+ prefs->fields[j].visible = 1;
+ }
+ for (i = 0; i < apol_vector_get_size(v); i++) {
+ char *s = apol_vector_get_element(v, i);
+ for (j = 0; j < num_visible_fields; j++) {
+ if (strcmp(s, prefs->fields[j].field) == 0) {
+ prefs->fields[j].visible = 0;
+ break;
+ }
+ }
+ }
+ free(value);
+ apol_vector_destroy(&v);
+ value = apol_config_get_var("REAL_TIME_LOG_MONITORING", file);
+ if (value != NULL && value[0] != '0') {
+ prefs->real_time_log = 1;
+ }
+ free(value);
+ value = apol_config_get_var("REAL_TIME_LOG_UPDATE_INTERVAL", file);
+ if (value != NULL) {
+ prefs->real_time_interval = atoi(value);
+ }
+ free(value);
+ cleanup:
+ free(path);
+ if (file != NULL) {
+ fclose(file);
+ }
+ if (error != 0) {
+ preferences_destroy(&prefs);
+ errno = error;
+ return NULL;
+ }
+ return prefs;
+}
+
+void preferences_destroy(preferences_t ** prefs)
+{
+ if (prefs != NULL && *prefs != NULL) {
+ free((*prefs)->log);
+ apol_policy_path_destroy(&(*prefs)->policy);
+ free((*prefs)->report);
+ free((*prefs)->stylesheet);
+ apol_vector_destroy(&(*prefs)->recent_log_files);
+ apol_vector_destroy(&(*prefs)->recent_policy_files);
+ free((*prefs)->fields);
+ free(*prefs);
+ *prefs = NULL;
+ }
+}
+
+int preferences_write_to_conf_file(preferences_t * prefs)
+{
+ FILE *file = NULL;
+ char *home, *conf_file = NULL, *value;
+ apol_vector_t *hidden_fields = NULL;
+ size_t i;
+ int retval = 0, error = 0;
+
+ /* we need to open ~/.seaudit */
+ home = getenv("HOME");
+ if (!home) {
+ error = EBADRQC;
+ goto cleanup;
+ }
+ if (asprintf(&conf_file, "%s/%s", home, USER_SEAUDIT_CONF) < 0) {
+ error = errno;
+ goto cleanup;
+ }
+
+ if ((file = fopen(conf_file, "w")) == NULL) {
+ error = errno;
+ goto cleanup;
+ }
+
+ fprintf(file, "# configuration file for seaudit - an audit log tool for Security Enhanced Linux.\n");
+ fprintf(file, "# this file is auto-generated\n\n");
+
+ if (strcmp(prefs->log, "") != 0) {
+ fprintf(file, "DEFAULT_LOG_FILE %s\n", prefs->log);
+ }
+ if (prefs->policy != NULL) {
+ value = apol_policy_path_to_string(prefs->policy);
+ if (value == NULL) {
+ error = errno;
+ goto cleanup;
+ }
+ fprintf(file, "DEFAULT_POLICY_PATH %s\n", value);
+ free(value);
+ }
+ if (strcmp(prefs->report, "") != 0) {
+ fprintf(file, "DEFAULT_REPORT_CONFIG_FILE %s\n", prefs->report);
+ }
+ if (strcmp(prefs->stylesheet, "") != 0) {
+ fprintf(file, "DEFAULT_REPORT_CSS_FILE %s\n", prefs->stylesheet);
+ }
+ if ((value = apol_str_join(prefs->recent_log_files, ":")) == NULL) {
+ error = errno;
+ goto cleanup;
+ }
+ fprintf(file, "RECENT_LOG_FILES %s\n", value);
+ free(value);
+
+ fprintf(file, "RECENT_POLICY_PATH_FILES %zd\n", apol_vector_get_size(prefs->recent_policy_files));
+ for (i = 0; i < apol_vector_get_size(prefs->recent_policy_files); i++) {
+ apol_policy_path_t *p = apol_vector_get_element(prefs->recent_policy_files, i);
+ if ((value = apol_policy_path_to_string(p)) == NULL) {
+ error = errno;
+ goto cleanup;
+ }
+ fprintf(file, "RECENT_POLICY_PATH_%zd %s\n", i, value);
+ free(value);
+ }
+
+ if ((hidden_fields = apol_vector_create(NULL)) == NULL) {
+ error = errno;
+ goto cleanup;
+ }
+ for (i = 0; i < num_visible_fields; i++) {
+ if (!prefs->fields[i].visible && apol_vector_append(hidden_fields, (char *)prefs->fields[i].field) < 0) {
+ error = errno;
+ goto cleanup;
+ }
+ }
+ if ((value = apol_str_join(hidden_fields, ":")) == NULL) {
+ error = errno;
+ goto cleanup;
+ }
+ fprintf(file, "LOG_COLUMNS_HIDDEN %s\n", value);
+ free(value);
+ fprintf(file, "REAL_TIME_LOG_MONITORING %d\n", prefs->real_time_log);
+ fprintf(file, "REAL_TIME_LOG_UPDATE_INTERVAL %d\n", prefs->real_time_interval);
+ retval = 0;
+ cleanup:
+ free(conf_file);
+ apol_vector_destroy(&hidden_fields);
+ if (file != NULL) {
+ fclose(file);
+ }
+ errno = error;
+ return retval;
+}
+
+int preferences_is_column_visible(preferences_t * prefs, preference_field_e id)
+{
+ size_t i;
+ for (i = 0; i < num_visible_fields; i++) {
+ if (prefs->fields[i].id == id) {
+ return prefs->fields[i].visible;
+ }
+ }
+ assert(0);
+ return -1;
+}
+
+void preferences_set_column_visible(preferences_t * prefs, preference_field_e id, int visible)
+{
+ size_t i;
+ for (i = 0; i < num_visible_fields; i++) {
+ if (prefs->fields[i].id == id) {
+ prefs->fields[i].visible = visible;
+ return;
+ }
+ }
+ assert(0);
+}
+
+int preferences_set_log(preferences_t * prefs, const char *log)
+{
+ char *s;
+ if ((s = strdup(log)) == NULL) {
+ return -1;
+ }
+ free(prefs->log);
+ prefs->log = s;
+ return 0;
+}
+
+const char *preferences_get_log(preferences_t * prefs)
+{
+ return prefs->log;
+}
+
+int preferences_set_policy(preferences_t * prefs, const apol_policy_path_t * policy)
+{
+ apol_policy_path_t *new_policy;
+ if ((new_policy = apol_policy_path_create_from_policy_path(policy)) == NULL) {
+ return -1;
+ }
+ apol_policy_path_destroy(&prefs->policy);
+ prefs->policy = new_policy;
+ return 0;
+}
+
+const apol_policy_path_t *preferences_get_policy(preferences_t * prefs)
+{
+ return prefs->policy;
+}
+
+int preferences_set_report(preferences_t * prefs, const char *report)
+{
+ char *s;
+ if ((s = strdup(report)) == NULL) {
+ return -1;
+ }
+ free(prefs->report);
+ prefs->report = s;
+ return 0;
+}
+
+const char *preferences_get_report(preferences_t * prefs)
+{
+ return prefs->report;
+}
+
+int preferences_set_stylesheet(preferences_t * prefs, const char *stylesheet)
+{
+ char *s;
+ if ((s = strdup(stylesheet)) == NULL) {
+ return -1;
+ }
+ free(prefs->stylesheet);
+ prefs->stylesheet = s;
+ return 0;
+}
+
+const char *preferences_get_stylesheet(preferences_t * prefs)
+{
+ return prefs->stylesheet;
+}
+
+void preferences_set_real_time_at_startup(preferences_t * prefs, int startup)
+{
+ prefs->real_time_log = startup;
+}
+
+int preferences_get_real_time_at_startup(preferences_t * prefs)
+{
+ return prefs->real_time_log;
+}
+
+void preferences_set_real_time_interval(preferences_t * prefs, int interval)
+{
+ if (interval <= 0) {
+ prefs->real_time_interval = 0;
+ } else {
+ prefs->real_time_interval = interval;
+ }
+}
+
+int preferences_get_real_time_interval(preferences_t * prefs)
+{
+ return prefs->real_time_interval;
+}
+
+/**
+ * Add an entry to a vector, discarding the oldest entry if the vector
+ * size is too large.
+ */
+static int prefs_add_recent_vector(apol_vector_t * v, const char *entry)
+{
+ size_t i;
+ char *s;
+ if (apol_vector_get_index(v, (void *)entry, apol_str_strcmp, NULL, &i) == 0) {
+ return 0;
+ }
+ if ((s = strdup(entry)) == NULL || apol_vector_append(v, s) < 0) {
+ int error = errno;
+ free(s);
+ errno = error;
+ return -1;
+ }
+ if (apol_vector_get_size(v) >= MAX_RECENT_ENTRIES) {
+ s = apol_vector_get_element(v, 0);
+ free(s);
+ return apol_vector_remove(v, 0);
+ }
+ return 0;
+}
+
+int preferences_add_recent_log(preferences_t * prefs, const char *log)
+{
+ return prefs_add_recent_vector(prefs->recent_log_files, log);
+}
+
+apol_vector_t *preferences_get_recent_logs(preferences_t * prefs)
+{
+ return prefs->recent_log_files;
+}
+
+static int preferences_policy_path_compare(const void *a, const void *b, void *data __attribute__ ((unused)))
+{
+ return apol_policy_path_compare((const apol_policy_path_t *)a, (const apol_policy_path_t *)b);
+}
+
+int preferences_add_recent_policy(preferences_t * prefs, const apol_policy_path_t * policy)
+{
+ size_t i;
+ apol_policy_path_t *p = NULL;
+ if (apol_vector_get_index(prefs->recent_policy_files, policy, preferences_policy_path_compare, NULL, &i) == 0) {
+ return 0;
+ }
+ if ((p = apol_policy_path_create_from_policy_path(policy)) == NULL || apol_vector_append(prefs->recent_policy_files, p) < 0) {
+ int error = errno;
+ apol_policy_path_destroy(&p);
+ errno = error;
+ return -1;
+ }
+ if (apol_vector_get_size(prefs->recent_policy_files) >= MAX_RECENT_ENTRIES) {
+ p = apol_vector_get_element(prefs->recent_policy_files, 0);
+ apol_policy_path_destroy(&p);
+ return apol_vector_remove(prefs->recent_policy_files, 0);
+ }
+ return 0;
+}
+
+apol_vector_t *preferences_get_recent_policies(preferences_t * prefs)
+{
+ return prefs->recent_policy_files;
+}