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; }
/* * This function examines the commandline parameters and sets various * search options. It returns a 0 on success and < 0 on failure */ int check_params(int count, char *vars[]) { int c = 1; int retval = 0; const char *optarg; if (count < 2) { usage(); return -1; } while (c < count && retval == 0) { // Go ahead and point to the next argument if (c+1 < count) { if (vars[c+1][0] != '-') optarg = vars[c+1]; else optarg = NULL; } else optarg = NULL; switch (audit_lookup_option(vars[c])) { case S_EVENT: if (!optarg) { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; break; } if (isdigit(optarg[0])) { errno = 0; event_id = strtoul(optarg, NULL, 10); if (errno) { fprintf(stderr, "Illegal value for audit event ID"); retval = -1; } c++; } else { fprintf(stderr, "Audit event id must be a numeric value, was %s\n", optarg); retval = -1; } break; case S_COMM: if (!optarg) { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; break; } else { event_comm = strdup(optarg); if (event_comm == NULL) retval = -1; c++; } break; case S_FILENAME: if (!optarg) { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; } else { event_filename = strdup(optarg); if (event_filename == NULL) retval = -1; c++; } break; case S_KEY: if (!optarg) { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; } else { event_key = strdup(optarg); if (event_key == NULL) retval = -1; c++; } break; case S_ALL_GID: if (!optarg) { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; break; } if (isdigit(optarg[0])) { errno = 0; event_gid = strtoul(optarg,NULL,10); if (errno) { fprintf(stderr, "Numeric group ID conversion error (%s) for %s\n", strerror(errno), optarg); retval = -1; } } else { struct group *gr ; gr = getgrnam(optarg) ; if (gr == NULL) { fprintf(stderr, "Group ID is non-numeric and unknown (%s)\n", optarg); retval = -1; break; } event_gid = gr->gr_gid; } event_egid = event_gid; event_ga = 1; c++; break; case S_EFF_GID: if (!optarg) { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; break; } if (isdigit(optarg[0])) { errno = 0; event_egid = strtoul(optarg,NULL,10); if (errno) { fprintf(stderr, "Numeric group ID conversion error (%s) for %s\n", strerror(errno), optarg); retval = -1; } } else { struct group *gr ; gr = getgrnam(optarg) ; if (gr == NULL) { fprintf(stderr, "Effective group ID is non-numeric and unknown (%s)\n", optarg); retval = -1; break; } event_egid = gr->gr_gid; } c++; break; case S_GID: if (!optarg) { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; break; } if (isdigit(optarg[0])) { errno = 0; event_gid = strtoul(optarg,NULL,10); if (errno) { fprintf(stderr, "Numeric group ID conversion error (%s) for %s\n", strerror(errno), optarg); retval = -1; } } else { struct group *gr ; gr = getgrnam(optarg) ; if (gr == NULL) { fprintf(stderr, "Group ID is non-numeric and unknown (%s)\n", optarg); retval = -1; break; } event_gid = gr->gr_gid; } c++; break; case S_HELP: usage(); exit(0); break; case S_HOSTNAME: if (!optarg) { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; } else { event_hostname = strdup(optarg); if (event_hostname == NULL) retval = -1; c++; } break; case S_INTERP: if (report_format == RPT_DEFAULT) report_format = RPT_INTERP; else { fprintf(stderr, "Conflicting output format %s\n", vars[c]); retval = -1; } if (optarg) { fprintf(stderr, "Argument is NOT required for %s\n", vars[c]); retval = -1; } break; case S_INFILE: if (!optarg) { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; } else { user_file = strdup(optarg); if (user_file == NULL) retval = -1; c++; } break; case S_MESSAGE_TYPE: if (!optarg) { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; } else { if (strcasecmp(optarg, "ALL") != 0) { retval = parse_msg(optarg); } c++; } if (retval < 0) { int i; fprintf(stderr, "Valid message types are: ALL "); for (i=AUDIT_USER;i<=AUDIT_LAST_VIRT_MSG;i++){ const char *name; if (i == AUDIT_WATCH_INS) // Skip a few i = AUDIT_FIRST_USER_MSG; name = audit_msg_type_to_name(i); if (name) fprintf(stderr, "%s ", name); } fprintf(stderr, "\n"); } break; case S_OBJECT: if (!optarg) { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; break; } else { event_object = strdup(optarg); if (event_object == NULL) retval = -1; c++; } break; case S_PPID: if (!optarg) { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; break; } if (isdigit(optarg[0])) { errno = 0; event_ppid = strtol(optarg,NULL,10); if (errno) retval = -1; c++; } else { fprintf(stderr, "Parent process id must be a numeric value, was %s\n", optarg); retval = -1; } break; case S_PID: if (!optarg) { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; break; } if (isdigit(optarg[0])) { errno = 0; event_pid = strtol(optarg,NULL,10); if (errno) retval = -1; c++; } else { fprintf(stderr, "Process id must be a numeric value, was %s\n", optarg); retval = -1; } break; case S_RAW: if (report_format == RPT_DEFAULT) report_format = RPT_RAW; else { fprintf(stderr, "Conflicting output format --raw\n"); retval = -1; } if (optarg) { fprintf(stderr, "Argument is NOT required for --raw\n"); retval = -1; } break; case S_NODE: if (!optarg) { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; } else { snode sn; c++; if (!event_node_list) { event_node_list = malloc(sizeof (slist)); if (!event_node_list) { retval = -1; break; } slist_create(event_node_list); } sn.str = strdup(optarg); sn.key = NULL; sn.hits=0; slist_append(event_node_list, &sn); } break; case S_SYSCALL: if (!optarg) { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; break; } if (isdigit(optarg[0])) { errno = 0; event_syscall = (int)strtoul(optarg, NULL, 10); if (errno) { fprintf(stderr, "Syscall numeric conversion error (%s) for %s\n", strerror(errno), optarg); retval = -1; } } else { int machine; machine = audit_detect_machine(); if (machine < 0) { fprintf(stderr, "Error detecting machine type"); retval = -1; break; } event_syscall = audit_name_to_syscall(optarg, machine); if (event_syscall == -1) { fprintf(stderr, "Syscall %s not found\n", optarg); retval = -1; } } c++; break; case S_CONTEXT: if (!optarg) { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; break; } else { event_subject = strdup(optarg); if (event_subject == NULL) retval = -1; event_object = strdup(optarg); if (event_object == NULL) retval = -1; event_se = 1; c++; } break; case S_SUBJECT: if (!optarg) { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; break; } else { event_subject = strdup(optarg); if (event_subject == NULL) retval = -1; c++; } break; case S_OSUCCESS: if (!optarg) { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; break; } if ( (strstr(optarg, "yes")!=NULL) || (strstr(optarg, "no")!=NULL) ) { if (strcmp(optarg, "yes") == 0) event_success = S_SUCCESS; else event_success = S_FAILED; } else { fprintf(stderr, "Success must be 'yes' or 'no'.\n"); retval = -1; } c++; break; case S_SESSION: if (!optarg) { if ((c+1 < count) && vars[c+1]) optarg = vars[c+1]; else { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; break; } } { size_t len = strlen(optarg); if (isdigit(optarg[0])) { errno = 0; event_session_id = strtol(optarg,NULL,10); if (errno) retval = -1; c++; } else if (len >= 2 && *(optarg)=='-' && (isdigit(optarg[1]))) { errno = 0; event_session_id = strtol(optarg, NULL, 0); if (errno) { retval = -1; fprintf(stderr, "Error converting %s\n", optarg); } c++; } else { fprintf(stderr, "Session id must be a numeric value, was %s\n", optarg); retval = -1; } } break; case S_EXIT: if (!optarg) { if ((c+1 < count) && vars[c+1]) optarg = vars[c+1]; else { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; break; } } { size_t len = strlen(optarg); if (isdigit(optarg[0])) { errno = 0; event_exit = strtol(optarg, NULL, 0); if (errno) { retval = -1; fprintf(stderr, "Error converting %s\n", optarg); } } else if (len >= 2 && *(optarg)=='-' && (isdigit(optarg[1]))) { errno = 0; event_exit = strtol(optarg, NULL, 0); if (errno) { retval = -1; fprintf(stderr, "Error converting %s\n", optarg); } } else { event_exit = audit_name_to_errno(optarg); if (event_exit == 0) { retval = -1; fprintf(stderr, "Unknown errno, was %s\n", optarg); } } c++; if (retval != -1) event_exit_is_set = 1; } break; case S_TIME_END: if (optarg) { if ( (c+2 < count) && vars[c+2] && (vars[c+2][0] != '-') ) { /* Have both date and time - check order*/ if (strchr(optarg, ':')) { if (ausearch_time_end(vars[c+2], optarg) != 0) retval = -1; } else { if (ausearch_time_end(optarg, vars[c+2]) != 0) retval = -1; } c++; } else { // Check against recognized words int t = lookup_time(optarg); if (t >= 0) { if (ausearch_time_end(optarg, NULL) != 0) retval = -1; } else if ( (strchr(optarg, ':')) == NULL) { /* Only have date */ if (ausearch_time_end(optarg, NULL) != 0) retval = -1; } else { /* Only have time */ if (ausearch_time_end(NULL, optarg) != 0) retval = -1; } } c++; break; } fprintf(stderr, "%s requires either date and/or time\n", vars[c]); retval = -1; break; case S_TIME_START: if (optarg) { if ( (c+2 < count) && vars[c+2] && (vars[c+2][0] != '-') ) { /* Have both date and time - check order */ if (strchr(optarg, ':')) { if (ausearch_time_start( vars[c+2], optarg) != 0) retval = -1; } else { if (ausearch_time_start(optarg, vars[c+2]) != 0) retval = -1; } c++; } else { // Check against recognized words int t = lookup_time(optarg); if (t >= 0) { if (ausearch_time_start(optarg, "00:00:00") != 0) retval = -1; } else if ( strchr(optarg, ':') == NULL) { /* Only have date */ if (ausearch_time_start(optarg, "00:00:00") != 0) retval = -1; } else { /* Only have time */ if (ausearch_time_start(NULL, optarg) != 0) retval = -1; } } c++; break; } fprintf(stderr, "%s requires either date and/or time\n", vars[c]); retval = -1; break; case S_TERMINAL: if (!optarg) { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; } else { event_terminal = strdup(optarg); if (event_terminal == NULL) retval = -1; c++; } break; case S_UID: if (!optarg) { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; break; } if (isdigit(optarg[0])) { errno = 0; event_uid = strtoul(optarg,NULL,10); if (errno) { fprintf(stderr, "Numeric user ID conversion error (%s) for %s\n", strerror(errno), optarg); retval = -1; } } else { struct passwd *pw; pw = getpwnam(optarg); if (pw == NULL) { fprintf(stderr, "Effective user ID is non-numeric and unknown (%s)\n", optarg); retval = -1; break; } event_uid = pw->pw_uid; } c++; break; case S_EFF_UID: if (!optarg) { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; break; } if (isdigit(optarg[0])) { errno = 0; event_euid = strtoul(optarg,NULL,10); if (errno) { fprintf(stderr, "Numeric user ID conversion error (%s) for %s\n", strerror(errno), optarg); retval = -1; } } else { struct passwd *pw ; pw = getpwnam(optarg) ; if (pw == NULL) { fprintf(stderr, "User ID is non-numeric and unknown (%s)\n", optarg); retval = -1; break; } event_euid = pw->pw_uid; } c++; break; case S_ALL_UID: if (!optarg) { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; break; } if (isdigit(optarg[0])) { errno = 0; event_uid = strtoul(optarg,NULL,10); if (errno) { fprintf(stderr, "Numeric user ID conversion error (%s) for %s\n", strerror(errno), optarg); retval = -1; } } else { struct passwd *pw ; pw = getpwnam(optarg) ; if (pw == NULL) { fprintf(stderr, "User ID is non-numeric and unknown (%s)\n", optarg); retval = -1; break; } event_uid = pw->pw_uid; } event_ua = 1; event_euid = event_uid; event_loginuid = event_uid; c++; break; case S_LOGINID: if (!optarg) { if ((c+1 < count) && vars[c+1]) optarg = vars[c+1]; else { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; break; } } { size_t len = strlen(optarg); if (isdigit(optarg[0])) { errno = 0; event_loginuid = strtoul(optarg,NULL,10); if (errno) { fprintf(stderr, "Numeric user ID conversion error (%s) for %s\n", strerror(errno), optarg); retval = -1; } } else if (len >= 2 && *(optarg)=='-' && (isdigit(optarg[1]))) { errno = 0; event_loginuid = strtol(optarg, NULL, 0); if (errno) { retval = -1; fprintf(stderr, "Error converting %s\n", optarg); } } else { struct passwd *pw ; pw = getpwnam(optarg) ; if (pw == NULL) { fprintf(stderr, "Login user ID is non-numeric and unknown (%s)\n", optarg); retval = -1; break; } event_loginuid = pw->pw_uid; } } c++; break; case S_UUID: if (!optarg) { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; } else { event_uuid = strdup(optarg); if (event_uuid == NULL) { retval = -1; } c++; } break; case S_VMNAME: if (!optarg) { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; } else { event_vmname= strdup(optarg); if (event_vmname == NULL) { retval = -1; } c++; } break; case S_VERSION: printf("ausearch version %s\n", VERSION); exit(0); break; case S_EXACT_MATCH: event_exact_match=1; break; case S_IN_LOGS: force_logs = 1; break; case S_JUST_ONE: just_one = 1; break; case S_EXECUTABLE: if (!optarg) { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; } else { event_exe = strdup(optarg); if (event_exe == NULL) retval = -1; c++; } break; case S_LINEBUFFERED: line_buffered = 1; break; default: fprintf(stderr, "%s is an unsupported option\n", vars[c]); retval = -1; break; } c++; } 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; }