diff options
Diffstat (limited to 'framework/src/audit/lib/libaudit.c')
-rw-r--r-- | framework/src/audit/lib/libaudit.c | 1606 |
1 files changed, 0 insertions, 1606 deletions
diff --git a/framework/src/audit/lib/libaudit.c b/framework/src/audit/lib/libaudit.c deleted file mode 100644 index 6311b813..00000000 --- a/framework/src/audit/lib/libaudit.c +++ /dev/null @@ -1,1606 +0,0 @@ -/* libaudit.c -- - * Copyright 2004-2009,2012,2014 Red Hat Inc., Durham, North Carolina. - * All Rights Reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; 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 <stdarg.h> -#include <string.h> -#include <stdlib.h> -#include <unistd.h> -#include <ctype.h> -#include <time.h> -#include <pwd.h> -#include <grp.h> -#include <errno.h> -#include <sys/poll.h> -#include <sys/utsname.h> -#include <sys/stat.h> -#include <fcntl.h> /* O_NOFOLLOW needs gnu defined */ -#include <limits.h> /* for PATH_MAX */ -#include <sys/stat.h> -#include <sys/types.h> - -#include "libaudit.h" -#include "private.h" -#include "errormsg.h" - -/* #defines for the audit failure query */ -#define CONFIG_FILE "/etc/libaudit.conf" - -/* Local prototypes */ -struct nv_pair -{ - const char *name; - const char *value; -}; - -struct kw_pair -{ - const char *name; - int (*parser)(const char *, int); -}; - -struct nv_list -{ - const char *name; - int option; -}; - -struct libaudit_conf -{ - auditfail_t failure_action; -}; - -static const struct nv_list failure_actions[] = -{ - {"ignore", FAIL_IGNORE }, - {"log", FAIL_LOG }, - {"terminate", FAIL_TERMINATE }, - { NULL, 0 } -}; - -int _audit_permadded = 0; -int _audit_archadded = 0; -int _audit_syscalladded = 0; -unsigned int _audit_elf = 0U; -static struct libaudit_conf config; - -static int audit_failure_parser(const char *val, int line); -static int audit_name_to_uid(const char *name, uid_t *uid); -static int audit_name_to_gid(const char *name, gid_t *gid); - -static const struct kw_pair keywords[] = -{ - {"failure_action", audit_failure_parser }, - { NULL, NULL } -}; - -static int audit_priority(int xerrno) -{ - /* If they've compiled their own kernel and did not include - * the audit susbsystem, they will get ECONNREFUSED. We'll - * demote the message to debug so its not lost entirely. */ - if (xerrno == ECONNREFUSED) - return LOG_DEBUG; - else - return LOG_WARNING; -} - -int audit_request_status(int fd) -{ - int rc = audit_send(fd, AUDIT_GET, NULL, 0); - if (rc < 0) - audit_msg(audit_priority(errno), - "Error sending status request (%s)", strerror(-rc)); - return rc; -} -hidden_def(audit_request_status) - -/* - * Set everything to its default value - */ -static void clear_config(void) -{ - config.failure_action = FAIL_IGNORE; -} - -/* Get 1 line from file */ -static char *get_line(FILE *f, char *buf, size_t len) -{ - if (fgets(buf, len, f)) { - /* remove newline */ - char *ptr = strchr(buf, 0x0a); - if (ptr) - *ptr = 0; - return buf; - } - return NULL; -} - -static int nv_split(char *buf, struct nv_pair *nv) -{ - /* Get the name part */ - char *ptr, *saved=NULL; - - nv->name = NULL; - nv->value = NULL; - ptr = audit_strsplit_r(buf, &saved); - if (ptr == NULL) - return 0; /* If there's nothing, go to next line */ - if (ptr[0] == '#') - return 0; /* If there's a comment, go to next line */ - nv->name = ptr; - - /* Check for a '=' */ - ptr = audit_strsplit_r(NULL, &saved); - if (ptr == NULL) - return 1; - if (strcmp(ptr, "=") != 0) - return 2; - - /* get the value */ - ptr = audit_strsplit_r(NULL, &saved); - if (ptr == NULL) - return 1; - nv->value = ptr; - - /* Make sure there's nothing else */ - ptr = audit_strsplit_r(NULL, &saved); - if (ptr) - return 1; - - /* Everything is OK */ - return 0; -} - -static const struct kw_pair *kw_lookup(const char *val) -{ - int i = 0; - while (keywords[i].name != NULL) { - if (strcasecmp(keywords[i].name, val) == 0) - break; - i++; - } - return &keywords[i]; -} - -static int audit_failure_parser(const char *val, int line) -{ - int i; - - audit_msg(LOG_DEBUG, "audit_failure_parser called with: %s", val); - for (i=0; failure_actions[i].name != NULL; i++) { - if (strcasecmp(val, failure_actions[i].name) == 0) { - config.failure_action = failure_actions[i].option; - return 0; - } - } - audit_msg(LOG_ERR, "Option %s not found - line %d", val, line); - return 1; -} - -/* - * Read the /etc/libaudit.conf file and all tunables. - */ -static int load_libaudit_config(const char *path) -{ - int fd, rc, lineno = 1; - struct stat st; - FILE *f; - char buf[128]; - - /* open the file */ - rc = open(path, O_NOFOLLOW|O_RDONLY); - if (rc < 0) { - if (errno != ENOENT) { - audit_msg(LOG_ERR, "Error opening %s (%s)", - path, strerror(errno)); - return 1; - } - audit_msg(LOG_WARNING, - "Config file %s doesn't exist, skipping", path); - return 0; - } - fd = rc; - - /* check the file's permissions: owned by root, not world writable, - * not symlink. - */ - audit_msg(LOG_DEBUG, "Config file %s opened for parsing", path); - if (fstat(fd, &st) < 0) { - audit_msg(LOG_ERR, "Error fstat'ing %s (%s)", - path, strerror(errno)); - close(fd); - return 1; - } - if (st.st_uid != 0) { - audit_msg(LOG_ERR, "Error - %s isn't owned by root", path); - close(fd); - return 1; - } - if ((st.st_mode & S_IWOTH) == S_IWOTH) { - audit_msg(LOG_ERR, "Error - %s is world writable", path); - close(fd); - return 1; - } - if (!S_ISREG(st.st_mode)) { - audit_msg(LOG_ERR, "Error - %s is not a regular file", path); - close(fd); - return 1; - } - - /* it's ok, read line by line */ - f = fdopen(fd, "rm"); - if (f == NULL) { - audit_msg(LOG_ERR, "Error - fdopen failed (%s)", - strerror(errno)); - close(fd); - return 1; - } - - while (get_line(f, buf, sizeof(buf))) { - // convert line into name-value pair - const struct kw_pair *kw; - struct nv_pair nv; - rc = nv_split(buf, &nv); - switch (rc) { - case 0: // fine - break; - case 1: // not the right number of tokens. - audit_msg(LOG_ERR, - "Wrong number of arguments for line %d in %s", - lineno, path); - break; - case 2: // no '=' sign - audit_msg(LOG_ERR, - "Missing equal sign for line %d in %s", - lineno, path); - break; - default: // something else went wrong... - audit_msg(LOG_ERR, - "Unknown error for line %d in %s", - lineno, path); - break; - } - if (nv.name == NULL) { - lineno++; - continue; - } - if (nv.value == NULL) { - fclose(f); - return 1; - } - - /* identify keyword or error */ - kw = kw_lookup(nv.name); - if (kw->name == NULL) { - audit_msg(LOG_ERR, - "Unknown keyword \"%s\" in line %d of %s", - nv.name, lineno, path); - fclose(f); - return 1; - } - - /* dispatch to keyword's local parser */ - rc = kw->parser(nv.value, lineno); - if (rc != 0) { - fclose(f); - return 1; // local parser puts message out - } - - lineno++; - } - - fclose(f); - return 0; -} - - -/* - * This function is called to get the value of the failure_action - * tunable stored in /etc/libaudit.conf. The function returns 1 if - * the tunable is not found or there is an error. If the tunable is found, - * 0 is returned the the tunable value is saved in the failmode parameter. - */ -int get_auditfail_action(auditfail_t *failmode) -{ - clear_config(); - - if (load_libaudit_config(CONFIG_FILE)) { - *failmode = config.failure_action; - return 1; - } - - *failmode = config.failure_action; - return 0; -} - -int audit_set_enabled(int fd, uint32_t enabled) -{ - int rc; - struct audit_status s; - - memset(&s, 0, sizeof(s)); - s.mask = AUDIT_STATUS_ENABLED; - s.enabled = enabled; - rc = audit_send(fd, AUDIT_SET, &s, sizeof(s)); - if (rc < 0) - audit_msg(audit_priority(errno), - "Error sending enable request (%s)", strerror(-rc)); - return rc; -} - -/* - * This function will return 0 if auditing is NOT enabled and - * 1 if enabled, and -1 on error. - */ -int audit_is_enabled(int fd) -{ - int rc; - - if (fd < 0) - return 0; - - if ((rc = audit_request_status(fd)) > 0) { - struct audit_reply rep; - int i; - int timeout = 40; /* tenths of seconds */ - struct pollfd pfd[1]; - - pfd[0].fd = fd; - pfd[0].events = POLLIN; - - for (i = 0; i < timeout; i++) { - do { - rc = poll(pfd, 1, 100); - } while (rc < 0 && errno == EINTR); - - rc = audit_get_reply(fd, &rep, GET_REPLY_NONBLOCKING,0); - if (rc > 0) { - /* If we get done or error, break out */ - if (rep.type == NLMSG_DONE || - rep.type == NLMSG_ERROR) - break; - - /* If its not status, keep looping */ - if (rep.type != AUDIT_GET) - continue; - - /* Found it... */ - return rep.status->enabled; - } - } - } - if (rc == -ECONNREFUSED) { - /* This is here to let people that build their own kernel - and disable the audit system get in. ECONNREFUSED is - issued by the kernel when there is "no on listening". */ - return 0; - } else if (rc == -EPERM && getuid() != 0) { - /* If we get this, then the kernel supports auditing - * but we don't have enough privilege to write to the - * socket. Therefore, we have already been authenticated - * and we are a common user. Just act as though auditing - * is not enabled. Any other error we take seriously. - * This is here basically to satisfy Xscreensaver. */ - return 0; - } - return -1; -} - -int audit_set_failure(int fd, uint32_t failure) -{ - int rc; - struct audit_status s; - - memset(&s, 0, sizeof(s)); - s.mask = AUDIT_STATUS_FAILURE; - s.failure = failure; - rc = audit_send(fd, AUDIT_SET, &s, sizeof(s)); - if (rc < 0) - audit_msg(audit_priority(errno), - "Error sending failure mode request (%s)", - strerror(-rc)); - return rc; -} - -/* - * This function returns -1 on error and 1 on success. - */ -int audit_set_pid(int fd, uint32_t pid, rep_wait_t wmode) -{ - struct audit_status s; - struct audit_reply rep; - struct pollfd pfd[1]; - int rc; - - memset(&s, 0, sizeof(s)); - s.mask = AUDIT_STATUS_PID; - s.pid = pid; - rc = audit_send(fd, AUDIT_SET, &s, sizeof(s)); - if (rc < 0) { - audit_msg(audit_priority(errno), - "Error setting audit daemon pid (%s)", - strerror(-rc)); - return rc; - } - if (wmode == WAIT_NO) - return 1; - - /* Now we'll see if there's any reply message. This only - happens on error. It is not fatal if there is no message. - As a matter of fact, we don't do anything with the message - besides gobble it. */ - pfd[0].fd = fd; - pfd[0].events = POLLIN; - do { - rc = poll(pfd, 1, 100); /* .1 second */ - } while (rc < 0 && errno == EINTR); - - (void)audit_get_reply(fd, &rep, GET_REPLY_NONBLOCKING, 0); - return 1; -} - -int audit_set_rate_limit(int fd, uint32_t limit) -{ - int rc; - struct audit_status s; - - memset(&s, 0, sizeof(s)); - s.mask = AUDIT_STATUS_RATE_LIMIT; - s.rate_limit = limit; - rc = audit_send(fd, AUDIT_SET, &s, sizeof(s)); - if (rc < 0) - audit_msg(audit_priority(errno), - "Error sending rate limit request (%s)", - strerror(-rc)); - return rc; -} - -int audit_set_backlog_limit(int fd, uint32_t limit) -{ - int rc; - struct audit_status s; - - memset(&s, 0, sizeof(s)); - s.mask = AUDIT_STATUS_BACKLOG_LIMIT; - s.backlog_limit = limit; - rc = audit_send(fd, AUDIT_SET, &s, sizeof(s)); - if (rc < 0) - audit_msg(audit_priority(errno), - "Error sending backlog limit request (%s)", - strerror(-rc)); - return rc; -} - -int audit_set_backlog_wait_time(int fd, uint32_t bwt) -{ - int rc = -1; -#if HAVE_DECL_AUDIT_VERSION_BACKLOG_WAIT_TIME - struct audit_status s; - - memset(&s, 0, sizeof(s)); - s.mask = AUDIT_STATUS_BACKLOG_WAIT_TIME; - s.backlog_wait_time = bwt; - rc = audit_send(fd, AUDIT_SET, &s, sizeof(s)); - if (rc < 0) - audit_msg(audit_priority(errno), - "Error sending backlog limit request (%s)", - strerror(-rc)); -#endif - return rc; -} - -int audit_set_feature(int fd, unsigned feature, unsigned value, unsigned lock) -{ -#if HAVE_DECL_AUDIT_FEATURE_VERSION - int rc; - struct audit_features f; - - memset(&f, 0, sizeof(f)); - f.mask = AUDIT_FEATURE_TO_MASK(feature); - if (value) - f.features = AUDIT_FEATURE_TO_MASK(feature); - if (lock) - f.lock = AUDIT_FEATURE_TO_MASK(feature); - rc = audit_send(fd, AUDIT_SET_FEATURE, &f, sizeof(f)); - if (rc < 0) - audit_msg(audit_priority(errno), - "Error setting feature (%s)", - strerror(-rc)); - return rc; -#else - errno = EINVAL; - return -1; -#endif -} -hidden_def(audit_set_feature) - -int audit_request_features(int fd) -{ -#if HAVE_DECL_AUDIT_FEATURE_VERSION - int rc; - struct audit_features f; - - memset(&f, 0, sizeof(f)); - rc = audit_send(fd, AUDIT_GET_FEATURE, &f, sizeof(f)); - if (rc < 0) - audit_msg(audit_priority(errno), - "Error getting feature (%s)", - strerror(-rc)); - return rc; -#else - errno = EINVAL; - return -1; -#endif -} -hidden_def(audit_request_features) - -extern int audit_set_loginuid_immutable(int fd) -{ -#if HAVE_DECL_AUDIT_FEATURE_VERSION - return audit_set_feature(fd, AUDIT_FEATURE_LOGINUID_IMMUTABLE, 1, 1); -#else - errno = EINVAL; - return -1; -#endif -} - -int audit_request_rules_list_data(int fd) -{ - int rc = audit_send(fd, AUDIT_LIST_RULES, NULL, 0); - if (rc < 0 && rc != -EINVAL) - audit_msg(audit_priority(errno), - "Error sending rule list data request (%s)", - strerror(-rc)); - return rc; -} - -int audit_request_signal_info(int fd) -{ - int rc = audit_send(fd, AUDIT_SIGNAL_INFO, NULL, 0); - if (rc < 0) - audit_msg(LOG_WARNING, - "Error sending signal_info request (%s)", - strerror(-rc)); - return rc; -} - -int audit_update_watch_perms(struct audit_rule_data *rule, int perms) -{ - int i, done=0; - - if (rule->field_count < 1) - return -1; - - // First see if we have an entry we are updating - for (i=0; i< rule->field_count; i++) { - if (rule->fields[i] == AUDIT_PERM) { - rule->values[i] = perms; - done = 1; - } - } - if (!done) { - // If not check to see if we have room to add a field - if (rule->field_count >= (AUDIT_MAX_FIELDS - 1)) - return -2; - - // Add the perm - rule->fields[rule->field_count] = AUDIT_PERM; - rule->fieldflags[rule->field_count] = AUDIT_EQUAL; - rule->values[rule->field_count] = perms; - rule->field_count++; - } - return 0; -} - -int audit_add_watch(struct audit_rule_data **rulep, const char *path) -{ - return audit_add_watch_dir(AUDIT_WATCH, rulep, path); -} - -int audit_add_dir(struct audit_rule_data **rulep, const char *path) -{ - return audit_add_watch_dir(AUDIT_DIR, rulep, path); -} - -int audit_add_watch_dir(int type, struct audit_rule_data **rulep, - const char *path) -{ - size_t len = strlen(path); - struct audit_rule_data *rule = *rulep; - - if (rule && rule->field_count) { - audit_msg(LOG_ERR, "Rule is not empty\n"); - return -1; - } - if (type != AUDIT_WATCH && type != AUDIT_DIR) { - audit_msg(LOG_ERR, "Invalid type used\n"); - return -1; - } - - *rulep = realloc(rule, len + sizeof(*rule)); - if (*rulep == NULL) { - free(rule); - audit_msg(LOG_ERR, "Cannot realloc memory!\n"); - return -1; - } - rule = *rulep; - memset(rule, 0, len + sizeof(*rule)); - - rule->flags = AUDIT_FILTER_EXIT; - rule->action = AUDIT_ALWAYS; - audit_rule_syscallbyname_data(rule, "all"); - rule->field_count = 2; - rule->fields[0] = type; - rule->values[0] = len; - rule->fieldflags[0] = AUDIT_EQUAL; - rule->buflen = len; - memcpy(&rule->buf[0], path, len); - - // Default to all permissions - rule->fields[1] = AUDIT_PERM; - rule->fieldflags[1] = AUDIT_EQUAL; - rule->values[1] = AUDIT_PERM_READ | AUDIT_PERM_WRITE | - AUDIT_PERM_EXEC | AUDIT_PERM_ATTR; - - _audit_permadded = 1; - - return 0; -} -hidden_def(audit_add_watch_dir) - -int audit_add_rule_data(int fd, struct audit_rule_data *rule, - int flags, int action) -{ - int rc; - - if (flags == AUDIT_FILTER_ENTRY) { - audit_msg(LOG_WARNING, "Use of entry filter is deprecated"); - return -2; - } - rule->flags = flags; - rule->action = action; - rc = audit_send(fd, AUDIT_ADD_RULE, rule, - sizeof(struct audit_rule_data) + rule->buflen); - if (rc < 0) - audit_msg(audit_priority(errno), - "Error sending add rule data request (%s)", - errno == EEXIST ? - "Rule exists" : strerror(-rc)); - return rc; -} - -int audit_delete_rule_data(int fd, struct audit_rule_data *rule, - int flags, int action) -{ - int rc; - - if (flags == AUDIT_FILTER_ENTRY) { - audit_msg(LOG_WARNING, "Use of entry filter is deprecated"); - return -2; - } - rule->flags = flags; - rule->action = action; - rc = audit_send(fd, AUDIT_DEL_RULE, rule, - sizeof(struct audit_rule_data) + rule->buflen); - if (rc < 0) { - if (rc == -ENOENT) - audit_msg(LOG_WARNING, - "Error sending delete rule request (No rule matches)"); - else - audit_msg(audit_priority(errno), - "Error sending delete rule data request (%s)", - strerror(-rc)); - } - return rc; -} - -/* - * This function is part of the directory auditing code - */ -int audit_trim_subtrees(int fd) -{ - int rc = audit_send(fd, AUDIT_TRIM, NULL, 0); - if (rc < 0) - audit_msg(audit_priority(errno), - "Error sending trim subtrees command (%s)", - strerror(-rc)); - return rc; -} - -/* - * This function is part of the directory auditing code - */ -int audit_make_equivalent(int fd, const char *mount_point, - const char *subtree) -{ - int rc; - size_t len1 = strlen(mount_point); - size_t len2 = strlen(subtree); - struct { - uint32_t sizes[2]; - unsigned char buf[]; - } *cmd = malloc(sizeof(*cmd) + len1 + len2); - - memset(cmd, 0, sizeof(*cmd) + len1 + len2); - - cmd->sizes[0] = len1; - cmd->sizes[1] = len2; - memcpy(&cmd->buf[0], mount_point, len1); - memcpy(&cmd->buf[len1], subtree, len2); - - rc = audit_send(fd, AUDIT_MAKE_EQUIV, cmd, sizeof(*cmd) + len1 + len2); - if (rc < 0) - audit_msg(audit_priority(errno), - "Error sending make_equivalent command (%s)", - strerror(-rc)); - free(cmd); - return rc; -} - -/* - * This function will retreive the loginuid or -1 if there - * is an error. - */ -uid_t audit_getloginuid(void) -{ - uid_t uid; - int len, in; - char buf[16]; - - errno = 0; - in = open("/proc/self/loginuid", O_NOFOLLOW|O_RDONLY); - if (in < 0) - return -1; - do { - len = read(in, buf, sizeof(buf)); - } while (len < 0 && errno == EINTR); - close(in); - if (len < 0 || len >= sizeof(buf)) - return -1; - buf[len] = 0; - errno = 0; - uid = strtol(buf, 0, 10); - if (errno) - return -1; - else - return uid; -} - -/* - * This function returns 0 on success and 1 on failure - */ -int audit_setloginuid(uid_t uid) -{ - char loginuid[16]; - int o, count, rc = 0; - - errno = 0; - count = snprintf(loginuid, sizeof(loginuid), "%u", uid); - o = open("/proc/self/loginuid", O_NOFOLLOW|O_WRONLY|O_TRUNC); - if (o >= 0) { - int block, offset = 0; - - while (count > 0) { - block = write(o, &loginuid[offset], (unsigned)count); - - if (block < 0) { - if (errno == EINTR) - continue; - audit_msg(LOG_ERR, "Error writing loginuid"); - close(o); - return 1; - } - offset += block; - count -= block; - } - close(o); - } else { - audit_msg(LOG_ERR, "Error opening /proc/self/loginuid"); - rc = 1; - } - return rc; -} - -int audit_rule_syscall_data(struct audit_rule_data *rule, int scall) -{ - int word = AUDIT_WORD(scall); - int bit = AUDIT_BIT(scall); - - if (word >= (AUDIT_BITMASK_SIZE-1)) - return -1; - rule->mask[word] |= bit; - return 0; -} -hidden_def(audit_rule_syscall_data) - -int audit_rule_syscallbyname_data(struct audit_rule_data *rule, - const char *scall) -{ - int nr, i; - int machine; - - if (!strcmp(scall, "all")) { - for (i = 0; i < (AUDIT_BITMASK_SIZE-1); i++) - rule->mask[i] = ~0; - return 0; - } - if (!_audit_elf) - machine = audit_detect_machine(); - else - machine = audit_elf_to_machine(_audit_elf); - if (machine < 0) - return -2; - nr = audit_name_to_syscall(scall, machine); - if (nr < 0) { - if (isdigit(scall[0])) - nr = strtol(scall, NULL, 0); - } - if (nr >= 0) - return audit_rule_syscall_data(rule, nr); - return -1; -} -hidden_def(audit_rule_syscallbyname_data) - -int audit_rule_interfield_comp_data(struct audit_rule_data **rulep, - const char *pair, - int flags) { - const char *f = pair; - char *v; - int op; - int field1, field2; - struct audit_rule_data *rule = *rulep; - - if (f == NULL) - return -1; - - if (rule->field_count >= (AUDIT_MAX_FIELDS - 1)) - return -28; - - /* look for 2-char operators first - then look for 1-char operators afterwards - when found, null out the bytes under the operators to split - and set value pointer just past operator bytes - */ - if ( (v = strstr(pair, "!=")) ) { - *v++ = '\0'; - *v++ = '\0'; - op = AUDIT_NOT_EQUAL; - } else if ( (v = strstr(pair, "=")) ) { - *v++ = '\0'; - op = AUDIT_EQUAL; - } else { - return -13; - } - - if (*f == 0) - return -24; - - if (*v == 0) - return -25; - - if ((field1 = audit_name_to_field(f)) < 0) - return -26; - - if ((field2 = audit_name_to_field(v)) < 0) - return -27; - - /* Interfield comparison can only be in exit filter */ - if (flags != AUDIT_FILTER_EXIT) - return -7; - - // It should always be AUDIT_FIELD_COMPARE - rule->fields[rule->field_count] = AUDIT_FIELD_COMPARE; - rule->fieldflags[rule->field_count] = op; - /* oh god, so many permutations */ - switch (field1) - { - /* UID comparison */ - case AUDIT_EUID: - switch(field2) { - case AUDIT_LOGINUID: - rule->values[rule->field_count] = AUDIT_COMPARE_AUID_TO_EUID; - break; - case AUDIT_FSUID: - rule->values[rule->field_count] = AUDIT_COMPARE_EUID_TO_FSUID; - break; - case AUDIT_OBJ_UID: - rule->values[rule->field_count] = AUDIT_COMPARE_EUID_TO_OBJ_UID; - break; - case AUDIT_SUID: - rule->values[rule->field_count] = AUDIT_COMPARE_EUID_TO_SUID; - break; - case AUDIT_UID: - rule->values[rule->field_count] = AUDIT_COMPARE_UID_TO_EUID; - break; - default: - return -1; - } - break; - case AUDIT_FSUID: - switch(field2) { - case AUDIT_LOGINUID: - rule->values[rule->field_count] = AUDIT_COMPARE_AUID_TO_FSUID; - break; - case AUDIT_EUID: - rule->values[rule->field_count] = AUDIT_COMPARE_EUID_TO_FSUID; - break; - case AUDIT_OBJ_UID: - rule->values[rule->field_count] = AUDIT_COMPARE_FSUID_TO_OBJ_UID; - break; - case AUDIT_SUID: - rule->values[rule->field_count] = AUDIT_COMPARE_SUID_TO_FSUID; - break; - case AUDIT_UID: - rule->values[rule->field_count] = AUDIT_COMPARE_UID_TO_FSUID; - break; - default: - return -1; - } - break; - case AUDIT_LOGINUID: - switch(field2) { - case AUDIT_EUID: - rule->values[rule->field_count] = AUDIT_COMPARE_AUID_TO_EUID; - break; - case AUDIT_FSUID: - rule->values[rule->field_count] = AUDIT_COMPARE_AUID_TO_FSUID; - break; - case AUDIT_OBJ_UID: - rule->values[rule->field_count] = AUDIT_COMPARE_AUID_TO_OBJ_UID; - break; - case AUDIT_SUID: - rule->values[rule->field_count] = AUDIT_COMPARE_AUID_TO_SUID; - break; - case AUDIT_UID: - rule->values[rule->field_count] = AUDIT_COMPARE_UID_TO_AUID; - break; - default: - return -1; - } - break; - case AUDIT_SUID: - switch(field2) { - case AUDIT_LOGINUID: - rule->values[rule->field_count] = AUDIT_COMPARE_AUID_TO_SUID; - break; - case AUDIT_EUID: - rule->values[rule->field_count] = AUDIT_COMPARE_EUID_TO_SUID; - break; - case AUDIT_FSUID: - rule->values[rule->field_count] = AUDIT_COMPARE_SUID_TO_FSUID; - break; - case AUDIT_OBJ_UID: - rule->values[rule->field_count] = AUDIT_COMPARE_SUID_TO_OBJ_UID; - break; - case AUDIT_UID: - rule->values[rule->field_count] = AUDIT_COMPARE_UID_TO_SUID; - break; - default: - return -1; - } - break; - case AUDIT_OBJ_UID: - switch(field2) { - case AUDIT_LOGINUID: - rule->values[rule->field_count] = AUDIT_COMPARE_AUID_TO_OBJ_UID; - break; - case AUDIT_EUID: - rule->values[rule->field_count] = AUDIT_COMPARE_EUID_TO_OBJ_UID; - break; - case AUDIT_FSUID: - rule->values[rule->field_count] = AUDIT_COMPARE_FSUID_TO_OBJ_UID; - break; - case AUDIT_UID: - rule->values[rule->field_count] = AUDIT_COMPARE_UID_TO_OBJ_UID; - break; - case AUDIT_SUID: - rule->values[rule->field_count] = AUDIT_COMPARE_SUID_TO_OBJ_UID; - break; - default: - return -1; - } - break; - case AUDIT_UID: - switch(field2) { - case AUDIT_LOGINUID: - rule->values[rule->field_count] = AUDIT_COMPARE_UID_TO_AUID; - break; - case AUDIT_EUID: - rule->values[rule->field_count] = AUDIT_COMPARE_UID_TO_EUID; - break; - case AUDIT_FSUID: - rule->values[rule->field_count] = AUDIT_COMPARE_UID_TO_FSUID; - break; - case AUDIT_OBJ_UID: - rule->values[rule->field_count] = AUDIT_COMPARE_UID_TO_OBJ_UID; - break; - case AUDIT_SUID: - rule->values[rule->field_count] = AUDIT_COMPARE_UID_TO_SUID; - break; - default: - return -1; - } - break; - - /* GID comparisons */ - case AUDIT_EGID: - switch(field2) { - case AUDIT_FSGID: - rule->values[rule->field_count] = AUDIT_COMPARE_EGID_TO_FSGID; - break; - case AUDIT_GID: - rule->values[rule->field_count] = AUDIT_COMPARE_GID_TO_EGID; - break; - case AUDIT_OBJ_GID: - rule->values[rule->field_count] = AUDIT_COMPARE_EGID_TO_OBJ_GID; - break; - case AUDIT_SGID: - rule->values[rule->field_count] = AUDIT_COMPARE_EGID_TO_SGID; - break; - default: - return -1; - } - break; - case AUDIT_FSGID: - switch(field2) { - case AUDIT_SGID: - rule->values[rule->field_count] = AUDIT_COMPARE_SGID_TO_FSGID; - break; - case AUDIT_GID: - rule->values[rule->field_count] = AUDIT_COMPARE_GID_TO_FSGID; - break; - case AUDIT_OBJ_GID: - rule->values[rule->field_count] = AUDIT_COMPARE_FSGID_TO_OBJ_GID; - break; - case AUDIT_EGID: - rule->values[rule->field_count] = AUDIT_COMPARE_EGID_TO_FSGID; - break; - default: - return -1; - } - break; - case AUDIT_GID: - switch(field2) { - case AUDIT_EGID: - rule->values[rule->field_count] = AUDIT_COMPARE_GID_TO_EGID; - break; - case AUDIT_FSGID: - rule->values[rule->field_count] = AUDIT_COMPARE_GID_TO_FSGID; - break; - case AUDIT_OBJ_GID: - rule->values[rule->field_count] = AUDIT_COMPARE_GID_TO_OBJ_GID; - break; - case AUDIT_SGID: - rule->values[rule->field_count] = AUDIT_COMPARE_GID_TO_SGID; - break; - default: - return -1; - } - break; - case AUDIT_OBJ_GID: - switch(field2) { - case AUDIT_EGID: - rule->values[rule->field_count] = AUDIT_COMPARE_EGID_TO_OBJ_GID; - break; - case AUDIT_FSGID: - rule->values[rule->field_count] = AUDIT_COMPARE_FSGID_TO_OBJ_GID; - break; - case AUDIT_GID: - rule->values[rule->field_count] = AUDIT_COMPARE_GID_TO_OBJ_GID; - break; - case AUDIT_SGID: - rule->values[rule->field_count] = AUDIT_COMPARE_SGID_TO_OBJ_GID; - break; - default: - return -1; - } - break; - case AUDIT_SGID: - switch(field2) { - case AUDIT_FSGID: - rule->values[rule->field_count] = AUDIT_COMPARE_SGID_TO_FSGID; - break; - case AUDIT_GID: - rule->values[rule->field_count] = AUDIT_COMPARE_GID_TO_SGID; - break; - case AUDIT_OBJ_GID: - rule->values[rule->field_count] = AUDIT_COMPARE_SGID_TO_OBJ_GID; - break; - case AUDIT_EGID: - rule->values[rule->field_count] = AUDIT_COMPARE_EGID_TO_SGID; - break; - default: - return -1; - } - break; - default: - return -1; - break; - } - rule->field_count++; - return 0; -} - -int audit_determine_machine(const char *arch) -{ // What do we want? i686, x86_64, ia64 or b64, b32 - int machine; - unsigned int bits = 0; - - if (strcasecmp("b64", arch) == 0) { - bits = __AUDIT_ARCH_64BIT; - machine = audit_detect_machine(); - } else if (strcasecmp("b32", arch) == 0) { - bits = ~__AUDIT_ARCH_64BIT; - machine = audit_detect_machine(); - } else { - machine = audit_name_to_machine(arch); - if (machine < 0) { - // See if its numeric - unsigned int ival; - errno = 0; - ival = strtoul(arch, NULL, 16); - if (errno) - return -4; - machine = audit_elf_to_machine(ival); - } - } - - if (machine < 0) - return -4; - - /* Here's where we fixup the machine. For example, they give - * x86_64 & want 32 bits we translate that to i686. */ - if (bits == ~__AUDIT_ARCH_64BIT && machine == MACH_86_64) - machine = MACH_X86; - else if (bits == ~__AUDIT_ARCH_64BIT && machine == MACH_PPC64) - machine = MACH_PPC; - else if (bits == ~__AUDIT_ARCH_64BIT && machine == MACH_S390X) - machine = MACH_S390; - else if (bits == ~__AUDIT_ARCH_64BIT && machine == MACH_AARCH64) - machine = MACH_ARM; - - /* Check for errors - return -6 - * We don't allow 32 bit machines to specify 64 bit. */ - switch (machine) - { - case MACH_X86: - if (bits == __AUDIT_ARCH_64BIT) - return -6; - break; - case MACH_IA64: - if (bits == ~__AUDIT_ARCH_64BIT) - return -6; - break; - case MACH_PPC: - if (bits == __AUDIT_ARCH_64BIT) - return -6; - break; - case MACH_S390: - if (bits == __AUDIT_ARCH_64BIT) - return -6; - break; -#ifdef WITH_ARM - case MACH_ARM: - if (bits == __AUDIT_ARCH_64BIT) - return -6; // Deadcode - just incase of mistake - break; -#endif -#ifdef WITH_AARCH64 - case MACH_AARCH64: - if (bits && bits != __AUDIT_ARCH_64BIT) - return -6; - break; -#endif - case MACH_86_64: /* fallthrough */ - case MACH_PPC64: /* fallthrough */ - case MACH_PPC64LE: /* fallthrough */ - case MACH_S390X: /* fallthrough */ - break; - default: - return -6; - } - return machine; -} - -int audit_rule_fieldpair_data(struct audit_rule_data **rulep, const char *pair, - int flags) -{ - const char *f = pair; - char *v; - int op; - int field; - int vlen; - int offset; - struct audit_rule_data *rule = *rulep; - - if (f == NULL) - return -1; - - if (rule->field_count >= (AUDIT_MAX_FIELDS - 1)) - return -28; - - /* look for 2-char operators first - then look for 1-char operators afterwards - when found, null out the bytes under the operators to split - and set value pointer just past operator bytes - */ - if ( (v = strstr(pair, "!=")) ) { - *v++ = '\0'; - *v++ = '\0'; - op = AUDIT_NOT_EQUAL; - } else if ( (v = strstr(pair, ">=")) ) { - *v++ = '\0'; - *v++ = '\0'; - op = AUDIT_GREATER_THAN_OR_EQUAL; - } else if ( (v = strstr(pair, "<=")) ) { - *v++ = '\0'; - *v++ = '\0'; - op = AUDIT_LESS_THAN_OR_EQUAL; - } else if ( (v = strstr(pair, "&=")) ) { - *v++ = '\0'; - *v++ = '\0'; - op = AUDIT_BIT_TEST; - } else if ( (v = strstr(pair, "=")) ) { - *v++ = '\0'; - op = AUDIT_EQUAL; - } else if ( (v = strstr(pair, ">")) ) { - *v++ = '\0'; - op = AUDIT_GREATER_THAN; - } else if ( (v = strstr(pair, "<")) ) { - *v++ = '\0'; - op = AUDIT_LESS_THAN; - } else if ( (v = strstr(pair, "&")) ) { - *v++ = '\0'; - op = AUDIT_BIT_MASK; - } - - if (v == NULL) - return -1; - - if (*f == 0) - return -22; - - if (*v == 0) - return -20; - - if ((field = audit_name_to_field(f)) < 0) - return -2; - - /* Exclude filter can be used only with MSGTYPE field */ - if (flags == AUDIT_FILTER_EXCLUDE && field != AUDIT_MSGTYPE) - return -12; - - rule->fields[rule->field_count] = field; - rule->fieldflags[rule->field_count] = op; - switch (field) - { - case AUDIT_UID: - case AUDIT_EUID: - case AUDIT_SUID: - case AUDIT_FSUID: - case AUDIT_LOGINUID: - case AUDIT_OBJ_UID: - // Do positive & negative separate for 32 bit systems - vlen = strlen(v); - if (isdigit((char)*(v))) - rule->values[rule->field_count] = - strtoul(v, NULL, 0); - else if (vlen >= 2 && *(v)=='-' && - (isdigit((char)*(v+1)))) - rule->values[rule->field_count] = - strtol(v, NULL, 0); - else { - if (strcmp(v, "unset") == 0) - rule->values[rule->field_count] = - 4294967295; - else if (audit_name_to_uid(v, - &rule->values[rule->field_count])) { - audit_msg(LOG_ERR, "Unknown user: %s", - v); - return -2; - } - } - break; - case AUDIT_GID: - case AUDIT_EGID: - case AUDIT_SGID: - case AUDIT_FSGID: - case AUDIT_OBJ_GID: - if (isdigit((char)*(v))) - rule->values[rule->field_count] = - strtol(v, NULL, 0); - else { - if (audit_name_to_gid(v, - &rule->values[rule->field_count])) { - audit_msg(LOG_ERR, "Unknown group: %s", - v); - return -2; - } - } - break; - case AUDIT_EXIT: - if (flags != AUDIT_FILTER_EXIT) - return -7; - vlen = strlen(v); - if (isdigit((char)*(v))) - rule->values[rule->field_count] = - strtol(v, NULL, 0); - else if (vlen >= 2 && *(v)=='-' && - (isdigit((char)*(v+1)))) - rule->values[rule->field_count] = - strtol(v, NULL, 0); - else { - rule->values[rule->field_count] = - audit_name_to_errno(v); - if (rule->values[rule->field_count] == 0) - return -15; - } - break; - case AUDIT_MSGTYPE: - if (flags != AUDIT_FILTER_EXCLUDE && - flags != AUDIT_FILTER_USER) - return -9; - - if (isdigit((char)*(v))) - rule->values[rule->field_count] = - strtol(v, NULL, 0); - else - if (audit_name_to_msg_type(v) > 0) - rule->values[rule->field_count] = - audit_name_to_msg_type(v); - else - return -8; - break; - /* These next few are strings */ - case AUDIT_OBJ_USER: - case AUDIT_OBJ_ROLE: - case AUDIT_OBJ_TYPE: - case AUDIT_OBJ_LEV_LOW: - case AUDIT_OBJ_LEV_HIGH: - case AUDIT_WATCH: - case AUDIT_DIR: - /* Watch & object filtering is invalid on anything - * but exit */ - if (flags != AUDIT_FILTER_EXIT) - return -7; - if (field == AUDIT_WATCH || field == AUDIT_DIR) - _audit_permadded = 1; - - /* fallthrough */ - case AUDIT_SUBJ_USER: - case AUDIT_SUBJ_ROLE: - case AUDIT_SUBJ_TYPE: - case AUDIT_SUBJ_SEN: - case AUDIT_SUBJ_CLR: - case AUDIT_FILTERKEY: - if (field == AUDIT_FILTERKEY && !(_audit_syscalladded || _audit_permadded)) - return -19; - vlen = strlen(v); - if (field == AUDIT_FILTERKEY && - vlen > AUDIT_MAX_KEY_LEN) - return -11; - else if (vlen > PATH_MAX) - return -11; - rule->values[rule->field_count] = vlen; - offset = rule->buflen; - rule->buflen += vlen; - *rulep = realloc(rule, sizeof(*rule) + rule->buflen); - if (*rulep == NULL) { - free(rule); - audit_msg(LOG_ERR, "Cannot realloc memory!\n"); - return -3; - } else { - rule = *rulep; - } - strncpy(&rule->buf[offset], v, vlen); - - break; - case AUDIT_ARCH: - if (_audit_syscalladded) - return -3; - if (!(op == AUDIT_NOT_EQUAL || op == AUDIT_EQUAL)) - return -13; - if (isdigit((char)*(v))) { - int machine; - - errno = 0; - _audit_elf = strtoul(v, NULL, 0); - if (errno) - return -5; - - // Make sure we have a valid mapping - machine = audit_elf_to_machine(_audit_elf); - if (machine < 0) - return -5; - } - else { - const char *arch=v; - unsigned int machine, elf; - machine = audit_determine_machine(arch); - /* OK, we have the machine type, now convert - to elf. */ - elf = audit_machine_to_elf(machine); - if (elf == 0) - return -5; - - _audit_elf = elf; - } - rule->values[rule->field_count] = _audit_elf; - _audit_archadded = 1; - break; - case AUDIT_PERM: - if (flags != AUDIT_FILTER_EXIT) - return -7; - else if (op != AUDIT_EQUAL) - return -13; - else { - unsigned int i, len, val = 0; - - len = strlen(v); - if (len > 4) - return -11; - - for (i = 0; i < len; i++) { - switch (tolower(v[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: - return -14; - } - } - rule->values[rule->field_count] = val; - } - break; - case AUDIT_FILETYPE: - if (!(flags == AUDIT_FILTER_EXIT || flags == AUDIT_FILTER_ENTRY)) - return -17; - rule->values[rule->field_count] = - audit_name_to_ftype(v); - if ((int)rule->values[rule->field_count] < 0) { - return -16; - } - break; - case AUDIT_ARG0...AUDIT_ARG3: - vlen = strlen(v); - if (isdigit((char)*(v))) - rule->values[rule->field_count] = - strtoul(v, NULL, 0); - else if (vlen >= 2 && *(v)=='-' && - (isdigit((char)*(v+1)))) - rule->values[rule->field_count] = - strtol(v, NULL, 0); - else - return -21; - break; - case AUDIT_DEVMAJOR...AUDIT_INODE: - case AUDIT_SUCCESS: - if (flags != AUDIT_FILTER_EXIT) - return -7; - /* fallthrough */ - default: - if (field == AUDIT_INODE) { - if (!(op == AUDIT_NOT_EQUAL || - op == AUDIT_EQUAL)) - return -13; - } - - if (field == AUDIT_PPID && !(flags == AUDIT_FILTER_EXIT - || flags == AUDIT_FILTER_ENTRY)) - return -17; - - if (!isdigit((char)*(v))) - return -21; - - if (field == AUDIT_INODE) - rule->values[rule->field_count] = - strtoul(v, NULL, 0); - else - rule->values[rule->field_count] = - strtol(v, NULL, 0); - break; - } - rule->field_count++; - return 0; -} - -void audit_rule_free_data(struct audit_rule_data *rule) -{ - free(rule); -} - -static int audit_name_to_uid(const char *name, uid_t *uid) -{ - struct passwd *pw; - - pw = getpwnam(name); - if (pw == NULL) - return 1; - - memset(pw->pw_passwd, ' ', strlen(pw->pw_passwd)); - *uid = pw->pw_uid; - return 0; -} - -static int audit_name_to_gid(const char *name, gid_t *gid) -{ - struct group *gr; - - gr = getgrnam(name); - if (gr == NULL) - return 1; - - *gid = gr->gr_gid; - return 0; -} - -int audit_detect_machine(void) -{ - struct utsname uts; - if (uname(&uts) == 0) -// strcpy(uts.machine, "x86_64"); - return audit_name_to_machine(uts.machine); - return -1; -} -hidden_def(audit_detect_machine) - -#ifndef NO_TABLES -void audit_number_to_errmsg(int errnumber, const char *opt) -{ - unsigned int i; - - for (i = 0; i < sizeof(err_msgtab)/sizeof(struct msg_tab); i++) { - if (err_msgtab[i].key == errnumber) { - switch (err_msgtab[i].position) - { - case 0: - fprintf(stderr, "%s\n", - err_msgtab[i].cvalue); - break; - case 1: - fprintf(stderr, "%s %s\n", opt, - err_msgtab[i].cvalue); - break; - case 2: - fprintf(stderr, "%s %s\n", - err_msgtab[i].cvalue, opt); - break; - default: - break; - } - return; - } - } -} -#endif |