summaryrefslogtreecommitdiffstats
path: root/framework/src/audit/lib/libaudit.c
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/audit/lib/libaudit.c')
-rw-r--r--framework/src/audit/lib/libaudit.c1606
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