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, ">")) ) { return -10; } else if ( (v = strstr(pair, "<")) ) { return -10; } else if ( (v = strstr(pair, "&")) ) { return -10; } else if ( (v = strstr(pair, "=")) ) { *v++ = '\0'; op = 0; // legacy // op = AUDIT_EQUAL; } if (v == NULL) return -1; if (*f == 0) return -22; if (*v == 0) return -20; 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: // 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 (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: 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", 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) 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; 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 (rule->values[rule->field_count] < 0) { return -16; } 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_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_NEGATE || op == 0)) return -13; } if (field == AUDIT_PPID && (flags != AUDIT_FILTER_EXIT && flags != AUDIT_FILTER_ENTRY)) return -17; if (flags == AUDIT_FILTER_EXCLUDE) return -18; 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; }
/* * 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(count, vars, "hicslDvtC:e:f:r:b:a:A:d:S:F:m:R:w:W:k:p:q:")) != 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': retval = audit_request_status(fd); if (retval <= 0) retval = -1; else retval = 0; /* success - just get the reply */ 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 { fprintf(stderr, "Enable must be 0, 1, or 2 was %s\n", 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 { fprintf(stderr, "Failure must be 0, 1, or 2 was %s\n", optarg); retval = -1; } break; case 'r': if (optarg && isdigit(optarg[0])) { uint32_t rate; errno = 0; rate = strtoul(optarg,NULL,0); if (errno) { fprintf(stderr, "Error converting rate\n"); return -1; } if (audit_set_rate_limit(fd, rate) > 0) audit_request_status(fd); else return -1; } else { fprintf(stderr, "Rate must be a numeric value was %s\n", optarg); retval = -1; } break; case 'b': if (optarg && isdigit(optarg[0])) { uint32_t limit; errno = 0; limit = strtoul(optarg,NULL,0); if (errno) { fprintf(stderr, "Error converting backlog\n"); return -1; } if (audit_set_backlog_limit(fd, limit) > 0) audit_request_status(fd); else return -1; } else { fprintf(stderr, "Backlog must be a numeric value was %s\n", optarg); retval = -1; } break; case 'l': if (count > 4 || count == 3) { fprintf(stderr, "Wrong number of options for list request\n"); retval = -1; break; } if (count == 4) { if (strcmp(vars[optind], "-k") == 0) { strncat(key, vars[3], keylen); count -= 2; } else { fprintf(stderr, "Only the -k option is allowed\n"); retval = -1; break; } } if (audit_request_rule_list(fd)) retval = -2; else retval = -1; break; case 'a': if (strstr(optarg, "task") && _audit_syscalladded) { fprintf(stderr, "Syscall auditing requested for task list\n"); retval = -1; } else { rc = audit_rule_setup(optarg, &add, &action, lineno); if (rc == 3) { fprintf(stderr, "Multiple rule insert/delete operations are not allowed\n"); retval = -1; } else if (rc == 2) { fprintf(stderr, "Append rule - bad keyword %s\n", optarg); retval = -1; } else if (rc == 1) { fprintf(stderr, "Append rule - possible is deprecated\n"); return -3; /* deprecated - eat it */ } else retval = 1; /* success - please send */ } break; case 'A': if (strstr(optarg, "task") && _audit_syscalladded) { fprintf(stderr, "Error: syscall auditing requested for task list\n"); retval = -1; } else { rc = audit_rule_setup(optarg, &add, &action, lineno); if (rc == 3) { fprintf(stderr, "Multiple rule insert/delete operations are not allowed\n"); retval = -1; } else if (rc == 2) { fprintf(stderr, "Add rule - bad keyword %s\n", optarg); retval = -1; } else if (rc == 1) { fprintf(stderr, "Append rule - possible is deprecated\n"); 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) { fprintf(stderr, "Multiple rule insert/delete operations are not allowed\n"); retval = -1; } else if (rc == 2) { fprintf(stderr, "Delete rule - bad keyword %s\n", optarg); retval = -1; } else if (rc == 1) { fprintf(stderr, "Delete rule - possible is deprecated\n"); 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)) { fprintf(stderr, "Error: syscall auditing being added to task list\n"); return -1; } else if (((add & (AUDIT_FILTER_MASK|AUDIT_FILTER_UNSET)) == AUDIT_FILTER_USER || (del & (AUDIT_FILTER_MASK|AUDIT_FILTER_UNSET)) == AUDIT_FILTER_USER)) { fprintf(stderr, "Error: syscall auditing being added to user list\n"); return -1; } else if (exclude) { fprintf(stderr, "Error: syscall auditing cannot be put on exclude list\n"); return -1; } else { if (unknown_arch) { int machine; unsigned int elf; machine = audit_detect_machine(); if (machine < 0) { fprintf(stderr, "Error detecting machine type\n"); return -1; } elf = audit_machine_to_elf(machine); if (elf == 0) { fprintf(stderr, "Error looking up elf type\n"); return -1; } _audit_elf = elf; } } rc = audit_rule_syscallbyname_data(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: fprintf(stderr, "Syscall name unknown: %s\n", optarg); retval = -1; break; case -2: fprintf(stderr, "Elf type unknown: 0x%x\n", _audit_elf); 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)) { fprintf(stderr, "List must be given before field\n"); 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) { fprintf(stderr, "The -m option must be only the only option and takes 1 parameter\n"); retval = -1; } else 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': fprintf(stderr, "Error - nested rule files not supported\n"); retval = -1; break; case 'D': if (count > 4 || count == 3) { fprintf(stderr, "Wrong number of options for Delete all request\n"); retval = -1; break; } if (count == 4) { if (strcmp(vars[optind], "-k") == 0) { strncat(key, vars[3], keylen); count -= 2; } else { fprintf(stderr, "Only the -k option is allowed\n"); 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) { fprintf(stderr, "watch option can't be given with a syscall\n"); retval = -1; } else if (optarg) { add = AUDIT_FILTER_EXIT; action = AUDIT_ALWAYS; _audit_syscalladded = 1; retval = audit_setup_watch_name(&rule_new, optarg); } else { fprintf(stderr, "watch option needs a path\n"); 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 { fprintf(stderr, "watch option needs a path\n"); retval = -1; } break; case 'k': if (!(_audit_syscalladded || _audit_permadded ) || (add==AUDIT_FILTER_UNSET && del==AUDIT_FILTER_UNSET)) { fprintf(stderr, "key option needs a watch or syscall given prior to it\n"); retval = -1; } else if (!optarg) { fprintf(stderr, "key option needs a value\n"); retval = -1; } else if ((strlen(optarg)+strlen(key)+(!!key[0])) > AUDIT_MAX_KEY_LEN) { fprintf(stderr, "key option exceeds size limit\n"); retval = -1; } else { if (strncmp(optarg, "ids-", 4) == 0) { if (check_ids_key(optarg)) { retval = -1; break; } } if (strchr(optarg, AUDIT_KEY_SEPARATOR)) fprintf(stderr, "key %s has illegal character\n", 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) { fprintf(stderr, "permission option needs a watch given prior to it\n"); retval = -1; } else if (!optarg) { fprintf(stderr, "permission option needs a filter\n"); retval = -1; } else retval = audit_setup_perms(rule_new, optarg); break; case 'q': if (_audit_syscalladded) { fprintf(stderr, "Syscall auditing requested for make equivalent\n"); retval = -1; } else { char *mp, *sub; retval = equiv_parse(optarg, &mp, &sub); if (retval < 0) { fprintf(stderr, "Error parsing equivalent parts\n"); 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; 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)) { fprintf(stderr, "parameter passed without an option given\n"); 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 */ asprintf(&cmd, "key=%s", key); if (cmd) { /* Add this to the rule */ int ret = audit_rule_fieldpair_data(&rule_new, cmd, flags); if (ret < 0) retval = -1; free(cmd); } else { fprintf(stderr, "Out of memory adding key\n"); retval = -1; } } if (retval == -1 && errno == ECONNREFUSED) fprintf(stderr, "The audit system is disabled\n"); return retval; }
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; /* 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: case AUDIT_OBJ_GID: // 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: 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 { // 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; #ifdef WITH_ARMEB case MACH_ARMEB: if (bits == __AUDIT_ARCH_64BIT) return -6; break; #endif #ifdef WITH_AARCH64 case MACH_AARCH64: if (bits != __AUDIT_ARCH_64BIT) return -6; break; #endif 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; 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; }