/* deprecated.c -- This file is the trash heap of things about to leave * Copyright 2006-07 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> */ #include "config.h" #include <errno.h> #include <string.h> #include <pwd.h> #include <grp.h> #include <ctype.h> #include <stdlib.h> #include <unistd.h> #include "libaudit.h" #include "private.h" extern int audit_archadded; extern int audit_syscalladded; extern unsigned int audit_elf; extern int audit_priority(int xerrno); int audit_request_rules_list(int fd) { int rc = audit_send(fd, AUDIT_LIST, NULL, 0); if (rc < 0) audit_msg(audit_priority(errno), "Error sending rule list request (%s)", strerror(-rc)); return rc; } hidden_def(audit_request_rules_list) int audit_add_rule(int fd, struct audit_rule *rule, int flags, int action) { int rc; rule->flags = flags; rule->action = action; rc = audit_send(fd, AUDIT_ADD, rule, sizeof(struct audit_rule)); if (rc < 0) audit_msg(audit_priority(errno), "Error sending add rule request (%s)", errno == EEXIST ? "Rule exists" : strerror(-rc)); return rc; } hidden_def(audit_add_rule) int audit_delete_rule(int fd, struct audit_rule *rule, int flags, int action) { int rc; rule->flags = flags; rule->action = action; rc = audit_send(fd, AUDIT_DEL, rule, sizeof(struct audit_rule)); 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 request (%s)", strerror(-rc)); } return rc; } hidden_def(audit_delete_rule) /* * This function will send a user space message to the kernel. * It returns the sequence number which is > 0 on success * or <= 0 on error. (pam uses this) This is the main audit sending * function now. */ int audit_send_user_message(int fd, int type, hide_t hide_error, const char *message) { int retry_cnt = 0; int rc; retry: rc = audit_send(fd, type, message, strlen(message)+1); 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 && hide_error == HIDE_IT) { /* 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; } else if (rc == -EINVAL) { /* If we get this, the kernel doesn't understand the * netlink message type. This is most likely due to * being an old kernel. Use the old message type. */ if (type >= AUDIT_FIRST_USER_MSG && type <= AUDIT_LAST_USER_MSG && !retry_cnt) { /* do retry */ type = AUDIT_USER; retry_cnt++; goto retry; } } return rc; } hidden_def(audit_send_user_message) int audit_rule_syscall(struct audit_rule *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) int audit_rule_syscallbyname(struct audit_rule *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(rule, nr); return -1; } hidden_def(audit_rule_syscallbyname) // Delete this with audit_rule_fieldpair static int 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; } // Delete this with audit_rule_fieldpair static int 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_rule_fieldpair(struct audit_rule *rule, const char *pair, int flags) { const char *f = pair; char *v; int op; int field; int vlen; if (f == NULL) return -1; /* 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_NEGATE; // legacy // 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 = 0; // legacy // 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 || f == v) return -1; audit_msg(LOG_DEBUG,"pair=%s\n", f); 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; audit_msg(LOG_DEBUG,"f%d%s%s\n", field, audit_operator_to_symbol(op),v); rule->fields[rule->field_count] = field | op; switch (field) { case AUDIT_UID: case AUDIT_EUID: case AUDIT_SUID: case AUDIT_FSUID: case AUDIT_LOGINUID: 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 { if (name_to_uid(v, &rule->values[rule->field_count])) { audit_msg(LOG_ERR, "Unknown user: %s", pair); return -2; } } break; case AUDIT_GID: case AUDIT_EGID: case AUDIT_SGID: case AUDIT_FSGID: if (isdigit((char)*(v))) rule->values[rule->field_count] = strtol(v, NULL, 0); else { if (name_to_gid(v, &rule->values[rule->field_count])) { audit_msg(LOG_ERR, "Unknown group: %s", pair); return -2; } } break; case AUDIT_EXIT: 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) 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; case AUDIT_ARCH: if (audit_syscalladded) return -3; if (!(op == AUDIT_NEGATE || op == 0)) 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 { // what do we want? i686, x86_64, ia64 // or b64, b32 int machine; unsigned int bits=0, elf; const char *arch=v; 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) 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; /* 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; case MACH_86_64: /* fallthrough */ case MACH_PPC64: /* fallthrough */ case MACH_S390X: /* fallthrough */ break; default: return -6; } /* 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; /* These are strings */ case AUDIT_SUBJ_USER: case AUDIT_SUBJ_ROLE: case AUDIT_SUBJ_TYPE: case AUDIT_SUBJ_SEN: case AUDIT_SUBJ_CLR: 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_PERM: case AUDIT_DIR: case AUDIT_FILTERKEY: return -10; case AUDIT_DEVMAJOR...AUDIT_INODE: case AUDIT_SUCCESS...AUDIT_SUCCESS: if (flags == AUDIT_FILTER_ENTRY) return -7; /* fallthrough */ default: if (field == AUDIT_INODE) { if (!(op == AUDIT_NEGATE || op == 0)) return -13; } rule->values[rule->field_count] = strtol(v, NULL, 0); break; } ++rule->field_count; return 0; } hidden_def(audit_rule_fieldpair) void audit_rule_free(struct audit_rule *rule) { free(rule); } hidden_def(audit_rule_free) // FIXME: delete this function after bumping the SONAME NUMBER int audit_log_avc(int fd, int type, const char *fmt, va_list ap) { type = fd; return 0; } hidden_def(audit_log_avc)