diff options
author | Ashlee Young <ashlee@wildernessvoice.com> | 2016-01-20 01:10:01 +0000 |
---|---|---|
committer | Ashlee Young <ashlee@wildernessvoice.com> | 2016-01-20 01:10:11 +0000 |
commit | 19d701ddf07d855128ded0cf2b573ce468e3bdd6 (patch) | |
tree | 0edcd3461ca903c76e431bb7c6348c42a0f12488 /framework/src/audit/src/auditctl.c | |
parent | fac6fbefbfad1cf837ddd88bc0d330559c8eb6f9 (diff) |
Removing Suricata and Audit from source repo, and updated build.sh to avoid building suricata. Will re-address this in C release via tar balls.
Change-Id: I3710076f8b7f3313cb3cb5260c4eb0a6834d4f6e
Signed-off-by: Ashlee Young <ashlee@wildernessvoice.com>
Diffstat (limited to 'framework/src/audit/src/auditctl.c')
-rw-r--r-- | framework/src/audit/src/auditctl.c | 1472 |
1 files changed, 0 insertions, 1472 deletions
diff --git a/framework/src/audit/src/auditctl.c b/framework/src/audit/src/auditctl.c deleted file mode 100644 index 334f8021..00000000 --- a/framework/src/audit/src/auditctl.c +++ /dev/null @@ -1,1472 +0,0 @@ -/* auditctl.c -- - * Copyright 2004-2015 Red Hat Inc., Durham, North Carolina. - * All Rights Reserved. - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Authors: - * Steve Grubb <sgrubb@redhat.com> - * Rickard E. (Rik) Faith <faith@redhat.com> - */ - -#include "config.h" -#include <stdio.h> -#include <stdlib.h> -#include <stdbool.h> -#include <string.h> /* strdup needs xopen define */ -#include <getopt.h> -#include <time.h> -#include <sys/stat.h> -#include <ctype.h> -#include <unistd.h> -#include <sys/utsname.h> -#include <fcntl.h> -#include <errno.h> -#include <libgen.h> /* For basename */ -#include <limits.h> /* PATH_MAX */ -#include "libaudit.h" -#include "auditctl-listing.h" -#include "private.h" - -/* This define controls the size of the line that we will request when - * reading in rules from a file. - */ -#define LINE_SIZE 6144 - - -/* Global functions */ -static int handle_request(int status); -static void get_reply(void); -extern int delete_all_rules(int fd); - -/* Global vars */ -int list_requested = 0, interpret = 0; -char key[AUDIT_MAX_KEY_LEN+1]; -const char key_sep[2] = { AUDIT_KEY_SEPARATOR, 0 }; -static int keylen; -static int fd = -1; -static int add = AUDIT_FILTER_UNSET, del = AUDIT_FILTER_UNSET, action = -1; -static int ignore = 0, continue_error = 0; -static int exclude = 0; -static int multiple = 0; -static struct audit_rule_data *rule_new = NULL; - -/* - * This function will reset everything used for each loop when loading - * a ruleset from a file. - */ -static int reset_vars(void) -{ - list_requested = 0; - _audit_syscalladded = 0; - _audit_permadded = 0; - _audit_archadded = 0; - _audit_elf = 0; - add = AUDIT_FILTER_UNSET; - del = AUDIT_FILTER_UNSET; - action = -1; - exclude = 0; - multiple = 0; - - free(rule_new); - rule_new = malloc(sizeof(struct audit_rule_data)); - memset(rule_new, 0, sizeof(struct audit_rule_data)); - if (fd < 0) { - if ((fd = audit_open()) < 0) { - audit_msg(LOG_ERR, "Cannot open netlink audit socket"); - return 1; - } - } - return 0; -} - -static void usage(void) -{ - printf( - "usage: auditctl [options]\n" - " -a <l,a> Append rule to end of <l>ist with <a>ction\n" - " -A <l,a> Add rule at beginning of <l>ist with <a>ction\n" - " -b <backlog> Set max number of outstanding audit buffers\n" - " allowed Default=64\n" - " -c Continue through errors in rules\n" - " -C f=f Compare collected fields if available:\n" - " Field name, operator(=,!=), field name\n" - " -d <l,a> Delete rule from <l>ist with <a>ction\n" - " l=task,exit,user,exclude\n" - " a=never,always\n" - " -D Delete all rules and watches\n" - " -e [0..2] Set enabled flag\n" - " -f [0..2] Set failure flag\n" - " 0=silent 1=printk 2=panic\n" - " -F f=v Build rule: field name, operator(=,!=,<,>,<=,\n" - " >=,&,&=) value\n" - " -h Help\n" - " -i Ignore errors when reading rules from file\n" - " -k <key> Set filter key on audit rule\n" - " -l List rules\n" - " -m text Send a user-space message\n" - " -p [r|w|x|a] Set permissions filter on watch\n" - " r=read, w=write, x=execute, a=attribute\n" - " -q <mount,subtree> make subtree part of mount point's dir watches\n" - " -r <rate> Set limit in messages/sec (0=none)\n" - " -R <file> read rules from file\n" - " -s Report status\n" - " -S syscall Build rule: syscall name or number\n" - " -t Trim directory watches\n" - " -v Version\n" - " -w <path> Insert watch at <path>\n" - " -W <path> Remove watch at <path>\n" - " --loginuid-immutable Make loginuids unchangeable once set\n" - " --backlog_wait_time Set the kernel backlog_wait_time\n" - ); -} - -static int lookup_filter(const char *str, int *filter) -{ - if (strcmp(str, "task") == 0) - *filter = AUDIT_FILTER_TASK; - else if (strcmp(str, "entry") == 0) - *filter = AUDIT_FILTER_ENTRY; - else if (strcmp(str, "exit") == 0) - *filter = AUDIT_FILTER_EXIT; - else if (strcmp(str, "user") == 0) - *filter = AUDIT_FILTER_USER; - else if (strcmp(str, "exclude") == 0) { - *filter = AUDIT_FILTER_EXCLUDE; - exclude = 1; - } else - return 2; - return 0; -} - -static int lookup_action(const char *str, int *act) -{ - if (strcmp(str, "never") == 0) - *act = AUDIT_NEVER; - else if (strcmp(str, "possible") == 0) - return 1; - else if (strcmp(str, "always") == 0) - *act = AUDIT_ALWAYS; - else - return 2; - return 0; -} - -/* - * Returns 0 ok, 1 deprecated action, 2 rule error, - * 3 multiple rule insert/delete - */ -static int audit_rule_setup(char *opt, int *filter, int *act, int lineno) -{ - int rc; - char *p; - - if (++multiple != 1) - return 3; - - p = strchr(opt, ','); - if (p == NULL || strchr(p+1, ',')) - return 2; - *p = 0; - - /* Try opt both ways */ - if (lookup_filter(opt, filter) == 2) { - rc = lookup_action(opt, act); - if (rc != 0) { - *p = ','; - return rc; - } - } - - /* Repair the string */ - *p = ','; - opt = p+1; - - /* If flags are empty, p+1 must be the filter */ - if (*filter == AUDIT_FILTER_UNSET) - lookup_filter(opt, filter); - else { - rc = lookup_action(opt, act); - if (rc != 0) - return rc; - } - - /* Make sure we set both */ - if (*filter == AUDIT_FILTER_UNSET || *act == -1) - return 2; - - /* Consolidate rules on exit filter */ - if (*filter == AUDIT_FILTER_ENTRY) { - *filter = AUDIT_FILTER_EXIT; - if (lineno) - audit_msg(LOG_INFO, "Warning - entry rules deprecated, changing to exit rule in line %d", lineno); - else - audit_msg(LOG_INFO, - "Warning - entry rules deprecated, changing to exit rule"); - } - - return 0; -} - -/* - * This function will check the path before accepting it. It returns - * 1 on error and 0 on success. - */ -static int check_path(const char *path) -{ - char *ptr, *base; - size_t nlen; - size_t plen = strlen(path); - if (plen >= PATH_MAX) { - audit_msg(LOG_ERR, "The path passed for the watch is too big"); - return 1; - } - if (path[0] != '/') { - audit_msg(LOG_ERR, "The path must start with '/'"); - return 1; - } - ptr = strdup(path); - base = basename(ptr); - nlen = strlen(base); - free(ptr); - if (nlen > NAME_MAX) { - audit_msg(LOG_ERR, "The base name of the path is too big"); - return 1; - } - - /* These are warnings, not errors */ - if (strstr(path, "..")) - audit_msg(LOG_WARNING, - "Warning - relative path notation is not supported"); - if (strchr(path, '*') || strchr(path, '?')) - audit_msg(LOG_WARNING, - "Warning - wildcard notation is not supported"); - - return 0; -} - -/* - * Setup a watch. The "name" of the watch in userspace will be the <path> to - * the watch. When this potential watch reaches the kernel, it will resolve - * down to <name> (of terminating file or directory). - * Returns a 1 on success & -1 on failure. - */ -static int audit_setup_watch_name(struct audit_rule_data **rulep, char *path) -{ - int type = AUDIT_WATCH; - size_t len; - struct stat buf; - - if (check_path(path)) - return -1; - - // Trim trailing '/' should they exist - len = strlen(path); - if (len > 2 && path[len-1] == '/') { - while (path[len-1] == '/' && len > 1) { - path[len-1] = 0; - len--; - } - } - if (stat(path, &buf) == 0) { - if (S_ISDIR(buf.st_mode)) - type = AUDIT_DIR; - } - /* FIXME: might want to check to see that rule is empty */ - if (audit_add_watch_dir(type, rulep, path)) - return -1; - - return 1; -} - -/* - * Setup a watch permissions. - * Returns a 1 on success & -1 on failure. - */ -static int audit_setup_perms(struct audit_rule_data *rule, const char *opt) -{ - unsigned int i, len, val = 0; - - len = strlen(opt); - if (len > 4) - return -1; - - for (i = 0; i < len; i++) { - switch (tolower(opt[i])) { - case 'r': - val |= AUDIT_PERM_READ; - break; - case 'w': - val |= AUDIT_PERM_WRITE; - break; - case 'x': - val |= AUDIT_PERM_EXEC; - break; - case 'a': - val |= AUDIT_PERM_ATTR; - break; - default: - audit_msg(LOG_ERR, - "Permission %c isn't supported", - opt[i]); - return -1; - } - } - - if (audit_update_watch_perms(rule_new, val) == 0) { - _audit_permadded = 1; - return 1; - } - return -1; -} - -/* 0 success, -1 failure */ -static int lookup_itype(const char *kind) -{ - if (strcmp(kind, "sys") == 0) - return 0; - if (strcmp(kind, "file") == 0) - return 0; - if (strcmp(kind, "exec") == 0) - return 0; - if (strcmp(kind, "mkexe") == 0) - return 0; - return -1; -} - -/* 0 success, -1 failure */ -static int lookup_iseverity(const char *severity) -{ - if (strncmp(severity, "inf", 3) == 0) - return 0; - if (strncmp(severity, "low", 3) == 0) - return 0; - if (strncmp(severity, "med", 3) == 0) - return 0; - if (strncmp(severity, "hi", 2) == 0) - return 0; - return -1; -} - -/* 0 success, -1 failure */ -static int check_ids_key(const char *k) -{ - char *ptr, *kindptr, *ratingptr; - char keyptr[AUDIT_MAX_KEY_LEN+1]; - - if (strlen(k) > AUDIT_MAX_KEY_LEN) - goto fail_exit; - - strncpy(keyptr, k, sizeof(keyptr)); - keyptr[AUDIT_MAX_KEY_LEN] = 0; - ptr = strchr(keyptr, '-'); // There has to be a - because strncmp - kindptr = ptr + 1; - if (*kindptr == 0) - goto fail_exit; - - ptr = strchr(kindptr, '-'); - if (ptr) { - *ptr = 0; - ratingptr = ptr +1; - } else // The rules are misconfigured - goto fail_exit; - if (*ratingptr == 0) - goto fail_exit; - - if (lookup_itype(kindptr)) { - audit_msg(LOG_ERR, "ids key type is bad"); - return -1; - } - if (lookup_iseverity(ratingptr)) { - audit_msg(LOG_ERR, "ids key severity is bad"); - return -1; - } - return 0; - -fail_exit: - audit_msg(LOG_ERR, "ids key is bad"); - return -1; -} - -static int equiv_parse(char *optarg, char **mp, char **sub) -{ - char *ptr = strchr(optarg, ','); - if (ptr == NULL) - return -1; // no comma - *ptr = 0; - ptr++; - if (*ptr == 0) - return -1; // ends with comma - *mp = optarg; - *sub = ptr; - if (strchr(*sub, ',')) - return -1; // too many commas - return 0; -} - -int audit_request_rule_list(int fd) -{ - if (audit_request_rules_list_data(fd) > 0) { - list_requested = 1; - get_reply(); - return 1; - } - return 0; -} - -void check_rule_mismatch(int lineno, const char *option) -{ - struct audit_rule_data tmprule; - unsigned int old_audit_elf = _audit_elf; - int rc = 0; - - switch (_audit_elf) - { - case AUDIT_ARCH_X86_64: - _audit_elf = AUDIT_ARCH_I386; - break; - case AUDIT_ARCH_PPC64: - _audit_elf = AUDIT_ARCH_PPC; - break; - case AUDIT_ARCH_S390X: - _audit_elf = AUDIT_ARCH_S390; - break; - } - memset(&tmprule, 0, sizeof(struct audit_rule_data)); - audit_rule_syscallbyname_data(&tmprule, option); - if (memcmp(tmprule.mask, rule_new->mask, AUDIT_BITMASK_SIZE)) - rc = 1; - _audit_elf = old_audit_elf; - if (rc) { - if (lineno) - audit_msg(LOG_WARNING, "WARNING - 32/64 bit syscall mismatch in line %d, you should specify an arch", lineno); - else - audit_msg(LOG_WARNING, "WARNING - 32/64 bit syscall mismatch, you should specify an arch"); - } -} - -int report_status(int fd) -{ - int retval; - - retval = audit_request_status(fd); - if (retval == -1) { - if (errno == ECONNREFUSED) - fprintf(stderr, "The audit system is disabled\n"); - return -1; - } - get_reply(); - retval = audit_request_features(fd); - if (retval == -1) { - // errno is EINVAL if the kernel does support features API - if (errno == EINVAL) - return -2; - return -1; - } - get_reply(); - return -2; -} - -int parse_syscall(struct audit_rule_data *rule_new, const char *optarg) -{ - int retval = 0; - char *saved; - - if (strchr(optarg, ',')) { - char *ptr, *tmp = strdup(optarg); - if (tmp == NULL) - return -1; - ptr = strtok_r(tmp, ",", &saved); - while (ptr) { - retval = audit_rule_syscallbyname_data(rule_new, ptr); - if (retval != 0) { - if (retval == -1) { - audit_msg(LOG_ERR, - "Syscall name unknown: %s", - ptr); - retval = -3; // error reported - } - break; - } - ptr = strtok_r(NULL, ",", &saved); - } - free(tmp); - return retval; - } - - return audit_rule_syscallbyname_data(rule_new, optarg); -} - -struct option long_opts[] = -{ - {"loginuid-immutable", 0, NULL, 1}, - {"backlog_wait_time", 1, NULL, 2}, - {NULL, 0, NULL, 0} -}; - -// FIXME: Change these to enums -/* - * returns: -3 deprecated, -2 success - no reply, -1 error - noreply, - * 0 success - reply, > 0 success - rule - */ -static int setopt(int count, int lineno, char *vars[]) -{ - int c; - int retval = 0, rc; - - optind = 0; - opterr = 0; - key[0] = 0; - keylen = AUDIT_MAX_KEY_LEN; - - while ((retval >= 0) && (c = getopt_long(count, vars, - "hicslDvtC:e:f:r:b:a:A:d:S:F:m:R:w:W:k:p:q:", - long_opts, NULL)) != EOF) { - int flags = AUDIT_FILTER_UNSET; - rc = 10; // Init to something impossible to see if unused. - switch (c) { - case 'h': - usage(); - retval = -1; - break; - case 'i': - ignore = 1; - retval = -2; - break; - case 'c': - ignore = 1; - continue_error = 1; - retval = -2; - break; - case 's': - if (count > 3) { - audit_msg(LOG_ERR, - "Too many options for status command"); - retval = -1; - break; - } else if (optind == 2 && count == 3) { - if (strcmp(vars[optind], "-i") == 0) { - interpret = 1; - count -= 1; - } else { - audit_msg(LOG_ERR, - "Only -i option is allowed"); - retval = -1; - break; - } - } - retval = report_status(fd); - break; - case 'e': - if (optarg && ((strcmp(optarg, "0") == 0) || - (strcmp(optarg, "1") == 0) || - (strcmp(optarg, "2") == 0))) { - if (audit_set_enabled(fd, strtoul(optarg,NULL,0)) > 0) - audit_request_status(fd); - else - retval = -1; - } else { - audit_msg(LOG_ERR, "Enable must be 0, 1, or 2 was %s", - optarg); - retval = -1; - } - break; - case 'f': - if (optarg && ((strcmp(optarg, "0") == 0) || - (strcmp(optarg, "1") == 0) || - (strcmp(optarg, "2") == 0))) { - if (audit_set_failure(fd, strtoul(optarg,NULL,0)) > 0) - audit_request_status(fd); - else - return -1; - } else { - audit_msg(LOG_ERR, "Failure must be 0, 1, or 2 was %s", - optarg); - retval = -1; - } - break; - case 'r': - if (optarg && isdigit(optarg[0])) { - uint32_t rate; - errno = 0; - rate = strtoul(optarg,NULL,0); - if (errno) { - audit_msg(LOG_ERR, "Error converting rate"); - return -1; - } - if (audit_set_rate_limit(fd, rate) > 0) - audit_request_status(fd); - else - return -1; - } else { - audit_msg(LOG_ERR,"Rate must be a numeric value was %s", - optarg); - retval = -1; - } - break; - case 'b': - if (optarg && isdigit(optarg[0])) { - uint32_t limit; - errno = 0; - limit = strtoul(optarg,NULL,0); - if (errno) { - audit_msg(LOG_ERR, "Error converting backlog"); - return -1; - } - if (audit_set_backlog_limit(fd, limit) > 0) - audit_request_status(fd); - else - return -1; - } else { - audit_msg(LOG_ERR, - "Backlog must be a numeric value was %s", - optarg); - retval = -1; - } - break; - case 'l': - if (count > 4) { - audit_msg(LOG_ERR, - "Wrong number of options for list request"); - retval = -1; - break; - } - if (count == 3) { - if (strcmp(vars[optind], "-i") == 0) { - interpret = 1; - count -= 1; - } else { - audit_msg(LOG_ERR, - "Only -k or -i options are allowed"); - retval = -1; - } - } else if (count == 4) { - if (vars[optind] && strcmp(vars[optind], "-k") == 0) { - strncat(key, vars[3], keylen); - count -= 2; - } else { - audit_msg(LOG_ERR, - "Only -k or -i options are allowed"); - retval = -1; - break; - } - } - if (audit_request_rule_list(fd)) { - list_requested = 1; - retval = -2; - } else - retval = -1; - break; - case 'a': - if (strstr(optarg, "task") && _audit_syscalladded) { - audit_msg(LOG_ERR, - "Syscall auditing requested for task list"); - retval = -1; - } else { - rc = audit_rule_setup(optarg, &add, &action, lineno); - if (rc == 3) { - audit_msg(LOG_ERR, - "Multiple rule insert/delete operations are not allowed\n"); - retval = -1; - } else if (rc == 2) { - audit_msg(LOG_ERR, - "Append rule - bad keyword %s", - optarg); - retval = -1; - } else if (rc == 1) { - audit_msg(LOG_ERR, - "Append rule - possible is deprecated"); - return -3; /* deprecated - eat it */ - } else - retval = 1; /* success - please send */ - } - break; - case 'A': - if (strstr(optarg, "task") && _audit_syscalladded) { - audit_msg(LOG_ERR, - "Error: syscall auditing requested for task list"); - retval = -1; - } else { - rc = audit_rule_setup(optarg, &add, &action, lineno); - if (rc == 3) { - audit_msg(LOG_ERR, - "Multiple rule insert/delete operations are not allowed"); - retval = -1; - } else if (rc == 2) { - audit_msg(LOG_ERR, - "Add rule - bad keyword %s", optarg); - retval = -1; - } else if (rc == 1) { - audit_msg(LOG_WARNING, - "Append rule - possible is deprecated"); - return -3; /* deprecated - eat it */ - } else { - add |= AUDIT_FILTER_PREPEND; - retval = 1; /* success - please send */ - } - } - break; - case 'd': - rc = audit_rule_setup(optarg, &del, &action, lineno); - if (rc == 3) { - audit_msg(LOG_ERR, - "Multiple rule insert/delete operations are not allowed"); - retval = -1; - } else if (rc == 2) { - audit_msg(LOG_ERR, "Delete rule - bad keyword %s", - optarg); - retval = -1; - } else if (rc == 1) { - audit_msg(LOG_INFO, - "Delete rule - possible is deprecated"); - return -3; /* deprecated - eat it */ - } else - retval = 1; /* success - please send */ - break; - case 'S': { - int unknown_arch = !_audit_elf; - /* Do some checking to make sure that we are not adding a - * syscall rule to a list that does not make sense. */ - if (((add & (AUDIT_FILTER_MASK|AUDIT_FILTER_UNSET)) == - AUDIT_FILTER_TASK || (del & - (AUDIT_FILTER_MASK|AUDIT_FILTER_UNSET)) == - AUDIT_FILTER_TASK)) { - audit_msg(LOG_ERR, - "Error: syscall auditing being added to task list"); - return -1; - } else if (((add & (AUDIT_FILTER_MASK|AUDIT_FILTER_UNSET)) == - AUDIT_FILTER_USER || (del & - (AUDIT_FILTER_MASK|AUDIT_FILTER_UNSET)) == - AUDIT_FILTER_USER)) { - audit_msg(LOG_ERR, - "Error: syscall auditing being added to user list"); - return -1; - } else if (exclude) { - audit_msg(LOG_ERR, - "Error: syscall auditing cannot be put on exclude list"); - return -1; - } else { - if (unknown_arch) { - int machine; - unsigned int elf; - machine = audit_detect_machine(); - if (machine < 0) { - audit_msg(LOG_ERR, - "Error detecting machine type"); - return -1; - } - elf = audit_machine_to_elf(machine); - if (elf == 0) { - audit_msg(LOG_ERR, - "Error looking up elf type %d", - machine); - return -1; - } - _audit_elf = elf; - } - } - rc = parse_syscall(rule_new, optarg); - switch (rc) - { - case 0: - _audit_syscalladded = 1; - if (unknown_arch && add != AUDIT_FILTER_UNSET) - check_rule_mismatch(lineno, optarg); - break; - case -1: - audit_msg(LOG_ERR, "Syscall name unknown: %s", - optarg); - retval = -1; - break; - case -2: - audit_msg(LOG_ERR, "Elf type unknown: 0x%x", - _audit_elf); - retval = -1; - break; - case -3: // Error reported - do nothing here - retval = -1; - break; - }} - break; - case 'F': - if (add != AUDIT_FILTER_UNSET) - flags = add & AUDIT_FILTER_MASK; - else if (del != AUDIT_FILTER_UNSET) - flags = del & AUDIT_FILTER_MASK; - // if the field is arch & there is a -t option...we - // can allow it - else if ((optind >= count) || (strstr(optarg, "arch=") == NULL) - || (strcmp(vars[optind], "-t") != 0)) { - audit_msg(LOG_ERR, "List must be given before field"); - retval = -1; - break; - } - - rc = audit_rule_fieldpair_data(&rule_new,optarg,flags); - if (rc != 0) { - audit_number_to_errmsg(rc, optarg); - retval = -1; - } else { - if (rule_new->fields[rule_new->field_count-1] == - AUDIT_PERM) - _audit_permadded = 1; - } - - break; - case 'C': - if (add != AUDIT_FILTER_UNSET) - flags = add & AUDIT_FILTER_MASK; - else if (del != AUDIT_FILTER_UNSET) - flags = del & AUDIT_FILTER_MASK; - - rc = audit_rule_interfield_comp_data(&rule_new, optarg, flags); - if (rc != 0) { - audit_number_to_errmsg(rc, optarg); - retval = -1; - } else { - if (rule_new->fields[rule_new->field_count - 1] == - AUDIT_PERM) - _audit_permadded = 1; - } - break; - case 'm': - if (count > 3) { - audit_msg(LOG_ERR, - "The -m option must be only the only option and takes 1 parameter"); - retval = -1; - } else { - const char*s = optarg; - while (*s) { - if (*s < 32) { - audit_msg(LOG_ERR, - "Illegal character in audit event"); - return -1; - } - s++; - } - if (audit_log_user_message( fd, AUDIT_USER, - optarg, NULL, NULL, NULL, 1) <= 0) - retval = -1; - else - return -2; // success - no reply for this - } - break; - case 'R': - audit_msg(LOG_ERR, "Error - nested rule files not supported"); - retval = -1; - break; - case 'D': - if (count > 4 || count == 3) { - audit_msg(LOG_ERR, - "Wrong number of options for Delete all request"); - retval = -1; - break; - } - if (count == 4) { - if (strcmp(vars[optind], "-k") == 0) { - strncat(key, vars[3], keylen); - count -= 2; - } else { - audit_msg(LOG_ERR, - "Only the -k option is allowed"); - retval = -1; - break; - } - } - retval = delete_all_rules(fd); - if (retval == 0) { - (void)audit_request_rule_list(fd); - key[0] = 0; - retval = -2; - } - break; - case 'w': - if (add != AUDIT_FILTER_UNSET || - del != AUDIT_FILTER_UNSET) { - audit_msg(LOG_ERR, - "watch option can't be given with a syscall"); - retval = -1; - } else if (optarg) { - add = AUDIT_FILTER_EXIT; - action = AUDIT_ALWAYS; - _audit_syscalladded = 1; - retval = audit_setup_watch_name(&rule_new, optarg); - } else { - audit_msg(LOG_ERR, "watch option needs a path"); - retval = -1; - } - break; - case 'W': - if (optarg) { - del = AUDIT_FILTER_EXIT; - action = AUDIT_ALWAYS; - _audit_syscalladded = 1; - retval = audit_setup_watch_name(&rule_new, optarg); - } else { - audit_msg(LOG_ERR, "watch option needs a path"); - retval = -1; - } - break; - case 'k': - if (!(_audit_syscalladded || _audit_permadded ) || - (add==AUDIT_FILTER_UNSET && - del==AUDIT_FILTER_UNSET)) { - audit_msg(LOG_ERR, - "key option needs a watch or syscall given prior to it"); - retval = -1; - } else if (!optarg) { - audit_msg(LOG_ERR, "key option needs a value"); - retval = -1; - } else if ((strlen(optarg)+strlen(key)+(!!key[0])) > - AUDIT_MAX_KEY_LEN) { - audit_msg(LOG_ERR, "key option exceeds size limit"); - retval = -1; - } else { - if (strncmp(optarg, "ids-", 4) == 0) { - if (check_ids_key(optarg)) { - retval = -1; - break; - } - } - if (strchr(optarg, AUDIT_KEY_SEPARATOR)) - audit_msg(LOG_ERR, - "key %s has illegal character", optarg); - if (key[0]) { // Add the separator if we need to - strcat(key, key_sep); - keylen--; - } - strncat(key, optarg, keylen); - keylen = AUDIT_MAX_KEY_LEN - strlen(key); - } - break; - case 'p': - if (!add && !del) { - audit_msg(LOG_ERR, - "permission option needs a watch given prior to it"); - retval = -1; - } else if (!optarg) { - audit_msg(LOG_ERR, "permission option needs a filter"); - retval = -1; - } else - retval = audit_setup_perms(rule_new, optarg); - break; - case 'q': - if (_audit_syscalladded) { - audit_msg(LOG_ERR, - "Syscall auditing requested for make equivalent"); - retval = -1; - } else { - char *mp, *sub; - retval = equiv_parse(optarg, &mp, &sub); - if (retval < 0) { - audit_msg(LOG_ERR, - "Error parsing equivalent parts"); - retval = -1; - } else { - retval = audit_make_equivalent(fd, mp, sub); - if (retval <= 0) { - retval = -1; - } else - return -2; // success - no reply needed - } - } - break; - case 't': - retval = audit_trim_subtrees(fd); - if (retval <= 0) - retval = -1; - else - return -2; // success - no reply for this - break; - case 'v': - printf("auditctl version %s\n", VERSION); - retval = -2; - break; - // Now the long options - case 1: - retval = audit_set_loginuid_immutable(fd); - if (retval <= 0) - retval = -1; - else - return -2; // success - no reply for this - break; - case 2: -#if HAVE_DECL_AUDIT_VERSION_BACKLOG_WAIT_TIME - if (optarg && isdigit(optarg[0])) { - uint32_t bwt; - errno = 0; - bwt = strtoul(optarg,NULL,0); - if (errno) { - audit_msg(LOG_ERR, - "Error converting backlog_wait_time"); - return -1; - } - if (audit_set_backlog_wait_time(fd, bwt) > 0) - audit_request_status(fd); - else - return -1; - } else { - audit_msg(LOG_ERR, - "Backlog_wait_time must be a numeric value was %s", - optarg); - retval = -1; - } -#else - audit_msg(LOG_ERR, - "backlog_wait_time is not supported on your kernel"); - retval = -1; -#endif - break; - default: - usage(); - retval = -1; - break; - } - } - /* catch extra args or errors where the user types "- s" */ - if (optind == 1) - retval = -1; - else if ((optind < count) && (retval != -1)) { - audit_msg(LOG_ERR, "parameter passed without an option given"); - retval = -1; - } - - /* See if we were adding a key */ - if (key[0] && list_requested == 0) { - int flags = 0; - char *cmd=NULL; - - /* Get the flag */ - if (add != AUDIT_FILTER_UNSET) - flags = add & AUDIT_FILTER_MASK; - else if (del != AUDIT_FILTER_UNSET) - flags = del & AUDIT_FILTER_MASK; - - /* Build the command */ - if (asprintf(&cmd, "key=%s", key) < 0) { - cmd = NULL; - audit_msg(LOG_ERR, "Out of memory adding key"); - retval = -1; - } else { - /* Add this to the rule */ - int ret = audit_rule_fieldpair_data(&rule_new, cmd, flags); - if (ret < 0) - retval = -1; - free(cmd); - } - } - if (retval == -1 && errno == ECONNREFUSED) - audit_msg(LOG_ERR, "The audit system is disabled"); - return retval; -} - -static char *get_line(FILE *f, char *buf) -{ - if (fgets_unlocked(buf, LINE_SIZE, f)) { - /* remove newline */ - char *ptr = strchr(buf, 0x0a); - if (ptr) - *ptr = 0; - return buf; - } - return NULL; -} - - -void preprocess(char *buf) -{ - unsigned int i = 0; - bool esc_ctx = false; - - while (buf[i]) { - if (buf[i] == '\\' && esc_ctx == false) - esc_ctx = true; - else { - if (esc_ctx == true) { - if (buf[i] == ' ') { - buf[i] = 0x07; - buf[i - 1] = 0x07; - } else if (buf[i] == '\\') { - buf[i] = 0x04; - buf[i - 1] = 0x04; - } - - esc_ctx = false; - } - } - - i++; - } -} - - -void postprocess(char *buf) -{ - char *str = strdup(buf); - char *pos1 = str; - char *pos2 = buf; - - if (!str) - return; - - while (*pos1) { - if (*pos1 == 0x07) { - *pos2 = ' '; - pos1 += 2; - pos2++; - continue; - } else if (*pos1 == 0x04) { - *pos2 = '\\'; - pos1 += 2; - pos2++; - continue; - } - - *pos2 = *pos1; - pos2++; - pos1++; - } - - *pos2 = 0; - free(str); -} - - -/* - * This function reads the given file line by line and executes the rule. - * It returns 0 if everything went OK, 1 if there are problems before reading - * the file and -1 on error conditions after executing some of the rules. - * It will abort reading the file if it encounters any problems. - */ -static int fileopt(const char *file) -{ - int i, tfd, rc, lineno = 1; - struct stat st; - FILE *f; - char buf[LINE_SIZE]; - - /* Does the file exist? */ - rc = open(file, O_RDONLY); - if (rc < 0) { - if (errno != ENOENT) { - audit_msg(LOG_ERR,"Error opening %s (%s)", - file, strerror(errno)); - return 1; - } - audit_msg(LOG_INFO, "file %s doesn't exist, skipping", file); - return 0; - } - tfd = rc; - - /* Is the file permissions sane? */ - if (fstat(tfd, &st) < 0) { - audit_msg(LOG_ERR, "Error fstat'ing %s (%s)", - file, strerror(errno)); - close(tfd); - return 1; - } - if (st.st_uid != 0) { - audit_msg(LOG_ERR, "Error - %s isn't owned by root", file); - close(tfd); - return 1; - } - if ((st.st_mode & S_IWOTH) == S_IWOTH) { - audit_msg(LOG_ERR, "Error - %s is world writable", file); - close(tfd); - return 1; - } - if (!S_ISREG(st.st_mode)) { - audit_msg(LOG_ERR, "Error - %s is not a regular file", file); - close(tfd); - return 1; - } - - f = fdopen(tfd, "rm"); - if (f == NULL) { - audit_msg(LOG_ERR, "Error - fdopen failed (%s)", - strerror(errno)); - close(tfd); - return 1; - } - - /* Read until eof, lineno starts as 1 */ - while (get_line(f, buf)) { - char *ptr, **fields; - int idx=0, nf = (strlen(buf)/3) + 3; - - /* Weed out blank lines */ - while (buf[idx] == ' ') - idx++; - if (buf[idx] == 0) { - lineno++; - continue; - } - - preprocess(buf); - ptr = audit_strsplit(buf); - if (ptr == NULL) - break; - - /* allow comments */ - if (ptr[0] == '#') { - lineno++; - continue; - } - i = 0; - fields = malloc(nf * sizeof(char *)); - fields[i++] = "auditctl"; - fields[i++] = ptr; - while( (ptr=audit_strsplit(NULL)) && (i < nf-1)) { - postprocess(ptr); - fields[i++] = ptr; - } - - fields[i] = NULL; - - /* Parse it */ - if (reset_vars()) { - free(fields); - fclose(f); - return -1; - } - rc = setopt(i, lineno, fields); - free(fields); - - /* handle reply or send rule */ - if (rc != -3) { - if (handle_request(rc) == -1) { - if (errno != ECONNREFUSED) - audit_msg(LOG_ERR, - "There was an error in line %d of %s", - lineno, file); - else { - audit_msg(LOG_ERR, - "The audit system is disabled"); - fclose(f); - return 0; - } - if (ignore == 0) { - fclose(f); - return -1; - } - if (continue_error) - continue_error = -1; - } - } - lineno++; - } - fclose(f); - return 0; -} - -/* Return 1 if ready, 0 otherwise */ -static int is_ready(int fd) -{ - if (audit_is_enabled(fd) == 2) { - audit_msg(LOG_ERR, "The audit system is in immutable mode," - " no rule changes allowed"); - return 0; - } else if (errno == ECONNREFUSED) { - audit_msg(LOG_ERR, "The audit system is disabled"); - return 0; - } - return 1; -} - -int main(int argc, char *argv[]) -{ - int retval = 1; - - set_aumessage_mode(MSG_STDERR, DBG_NO); - - if (argc == 1) { - usage(); - return 1; - } -#ifndef DEBUG - /* Make sure we are root if we do anything except help */ - if (!(argc == 2 && (strcmp(argv[1], "--help")==0 || - strcmp(argv[1], "-h") == 0)) && (geteuid() != 0)) { - audit_msg(LOG_WARNING, "You must be root to run this program."); - return 4; - } -#endif - /* Check where the rules are coming from: commandline or file */ - if ((argc == 3) && (strcmp(argv[1], "-R") == 0)) { - // If reading a file, its most likely start up. Send problems - // to syslog where they will persist for later review - set_aumessage_mode(MSG_SYSLOG, DBG_NO); - fd = audit_open(); - if (is_ready(fd) == 0) - return 0; - else if (fileopt(argv[2])) { - free(rule_new); - return 1; - } else { - free(rule_new); - if (continue_error < 0) - return 1; - return 0; - } - } else { - if (reset_vars()) { - free(rule_new); - return 1; - } - retval = setopt(argc, 0, argv); - if (retval == -3) { - free(rule_new); - return 0; - } - } - - if (add != AUDIT_FILTER_UNSET || del != AUDIT_FILTER_UNSET) { - fd = audit_open(); - if (is_ready(fd) == 0) { - free(rule_new); - return 0; - } - } - retval = handle_request(retval); - free(rule_new); - return retval; -} - -/* - * This function is called after setopt to handle the return code. - * On entry, status = 0 means just get the reply. Greater than 0 means we - * are adding or deleting a rule or watch. -1 means an error occurred. - * -2 means everything is OK and no reply needed. Even if there's an - * error, we need to call this routine to close up the audit fd. - * The return code from this function is 0 success and -1 error. - */ -static int handle_request(int status) -{ - if (status == 0) { - if (_audit_syscalladded) { - audit_msg(LOG_ERR, "Error - no list specified"); - return -1; - } - get_reply(); - } else if (status == -2) - status = 0; // report success - else if (status > 0) { - int rc; - if (add != AUDIT_FILTER_UNSET) { - // if !task add syscall any if not specified - if ((add & AUDIT_FILTER_MASK) != AUDIT_FILTER_TASK && - _audit_syscalladded != 1) { - audit_rule_syscallbyname_data( - rule_new, "all"); - } - set_aumessage_mode(MSG_QUIET, DBG_NO); - rc = audit_add_rule_data(fd, rule_new, add, action); - set_aumessage_mode(MSG_STDERR, DBG_NO); - /* Retry for legacy kernels */ - if (rc < 0) { - if (errno == EINVAL && - rule_new->fields[0] == AUDIT_DIR) { - rule_new->fields[0] = AUDIT_WATCH; - rc = audit_add_rule_data(fd, rule_new, - add, action); - } else { - audit_msg(LOG_ERR, - "Error sending add rule data request (%s)", - errno == EEXIST ? - "Rule exists" : strerror(-rc)); - } - } - } - else if (del != AUDIT_FILTER_UNSET) { - if ((del & AUDIT_FILTER_MASK) != AUDIT_FILTER_TASK && - _audit_syscalladded != 1) { - audit_rule_syscallbyname_data( - rule_new, "all"); - } - set_aumessage_mode(MSG_QUIET, DBG_NO); - rc = audit_delete_rule_data(fd, rule_new, - del, action); - set_aumessage_mode(MSG_STDERR, DBG_NO); - /* Retry for legacy kernels */ - if (rc < 0) { - if (errno == EINVAL && - rule_new->fields[0] == AUDIT_DIR) { - rule_new->fields[0] = AUDIT_WATCH; - rc = audit_delete_rule_data(fd,rule_new, - del, action); - } else { - audit_msg(LOG_ERR, - "Error sending delete rule data request (%s)", - errno == EEXIST ? - "Rule exists" : strerror(-rc)); - } - } - } else { - usage(); - audit_close(fd); - exit(1); - } - if (rc <= 0) - status = -1; - else - status = 0; - } else - status = -1; - - if (!list_requested) - audit_close(fd); - fd = -1; - return status; -} - -/* - * A reply from the kernel is expected. Get and display it. - */ -static void get_reply(void) -{ - int i, retval; - int timeout = 40; /* loop has delay of .1 - so this is 4 seconds */ - struct audit_reply rep; - fd_set read_mask; - FD_ZERO(&read_mask); - FD_SET(fd, &read_mask); - - // Reset printing counter - audit_print_init(); - - for (i = 0; i < timeout; i++) { - struct timeval t; - - t.tv_sec = 0; - t.tv_usec = 100000; /* .1 second */ - do { - retval=select(fd+1, &read_mask, NULL, NULL, &t); - } while (retval < 0 && errno == EINTR); - // We'll try to read just in case - retval = audit_get_reply(fd, &rep, GET_REPLY_NONBLOCKING, 0); - if (retval > 0) { - if (rep.type == NLMSG_ERROR && rep.error->error == 0) { - i = 0; /* reset timeout */ - continue; /* This was an ack */ - } - - if ((retval = audit_print_reply(&rep, fd)) == 0) - break; - else - i = 0; /* If getting more, reset timeout */ - } - } -} - |