Example #1
0
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;

	/* 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;
}
Example #2
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, ">")) ) {
		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;
}
Example #3
0
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;
}