Example #1
0
static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
{
	u32			uid, pid, seq;
	void			*data;
	struct audit_status	*status_get, status_set;
	struct audit_login	*login;
	int			err = 0;
	struct audit_buffer	*ab;

	pid  = NETLINK_CREDS(skb)->pid;
	uid  = NETLINK_CREDS(skb)->uid;
	seq  = nlh->nlmsg_seq;
	data = NLMSG_DATA(nlh);

	switch (nlh->nlmsg_type) {
	case AUDIT_GET:
		status_set.enabled	 = audit_enabled;
		status_set.failure	 = audit_failure;
		status_set.pid		 = audit_pid;
		status_set.rate_limit	 = audit_rate_limit;
		status_set.backlog_limit = audit_backlog_limit;
		status_set.lost		 = atomic_read(&audit_lost);
		status_set.backlog	 = atomic_read(&audit_backlog);
		audit_send_reply(pid, seq, AUDIT_GET, 0, 0,
				 &status_set, sizeof(status_set));
		break;
	case AUDIT_SET:
		if (!capable(CAP_SYS_ADMIN))
			return -EPERM;
		status_get   = (struct audit_status *)data;
		if (status_get->mask & AUDIT_STATUS_ENABLED) {
			err = audit_set_enabled(status_get->enabled);
			if (err < 0) return err;
		}
		if (status_get->mask & AUDIT_STATUS_FAILURE) {
			err = audit_set_failure(status_get->failure);
			if (err < 0) return err;
		}
		if (status_get->mask & AUDIT_STATUS_PID) {
			int old   = audit_pid;
			audit_pid = status_get->pid;
			audit_log(current->audit_context,
				  "audit_pid=%d old=%d", audit_pid, old);
		}
		if (status_get->mask & AUDIT_STATUS_RATE_LIMIT)
			audit_set_rate_limit(status_get->rate_limit);
		if (status_get->mask & AUDIT_STATUS_BACKLOG_LIMIT)
			audit_set_backlog_limit(status_get->backlog_limit);
		break;
	case AUDIT_USER:
		ab = audit_log_start(NULL);
		if (!ab)
			break;	/* audit_panic has been called */
		audit_log_format(ab,
				 "user pid=%d uid=%d length=%d msg='%.1024s'",
				 pid, uid,
				 (int)(nlh->nlmsg_len
				       - ((char *)data - (char *)nlh)),
				 (char *)data);
		ab->type = AUDIT_USER;
		ab->pid  = pid;
		audit_log_end(ab);
		break;
	case AUDIT_LOGIN:
		if (!capable(CAP_SYS_ADMIN))
			return -EPERM;
		login = (struct audit_login *)data;
		ab = audit_log_start(NULL);
		if (ab) {
			audit_log_format(ab, "login pid=%d uid=%d loginuid=%d"
					 " length=%d msg='%.1024s'",
					 pid, uid,
					 login->loginuid,
					 login->msglen,
					 login->msg);
			ab->type = AUDIT_LOGIN;
			ab->pid  = pid;
			audit_log_end(ab);
		}
#ifdef CONFIG_AUDITSYSCALL
		err = audit_set_loginuid(current->audit_context,
					 login->loginuid);
#endif
		break;
	case AUDIT_LIST:
	case AUDIT_ADD:
	case AUDIT_DEL:
#ifdef CONFIG_AUDITSYSCALL
		err = audit_receive_filter(nlh->nlmsg_type, pid, uid, seq,
					   data);
#else
		err = -EOPNOTSUPP;
#endif
		break;
	default:
		err = -EINVAL;
		break;
	}

	return err < 0 ? err : 0;
}
Example #2
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;
}
Example #3
0
static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
{
	u32			uid, pid, seq;
	void			*data;
	struct audit_status	*status_get, status_set;
	int			err;
	struct audit_buffer	*ab;
	u16			msg_type = nlh->nlmsg_type;
	uid_t			loginuid; /* loginuid of sender */
	struct audit_sig_info   sig_data;

	err = audit_netlink_ok(NETLINK_CB(skb).eff_cap, msg_type);
	if (err)
		return err;

	/* As soon as there's any sign of userspace auditd, start kauditd to talk to it */
	if (!kauditd_task)
		kauditd_task = kthread_run(kauditd_thread, NULL, "kauditd");
	if (IS_ERR(kauditd_task)) {
		err = PTR_ERR(kauditd_task);
		kauditd_task = NULL;
		return err;
	}

	pid  = NETLINK_CREDS(skb)->pid;
	uid  = NETLINK_CREDS(skb)->uid;
	loginuid = NETLINK_CB(skb).loginuid;
	seq  = nlh->nlmsg_seq;
	data = NLMSG_DATA(nlh);

	switch (msg_type) {
	case AUDIT_GET:
		status_set.enabled	 = audit_enabled;
		status_set.failure	 = audit_failure;
		status_set.pid		 = audit_pid;
		status_set.rate_limit	 = audit_rate_limit;
		status_set.backlog_limit = audit_backlog_limit;
		status_set.lost		 = atomic_read(&audit_lost);
		status_set.backlog	 = skb_queue_len(&audit_skb_queue);
		audit_send_reply(NETLINK_CB(skb).pid, seq, AUDIT_GET, 0, 0,
				 &status_set, sizeof(status_set));
		break;
	case AUDIT_SET:
		if (nlh->nlmsg_len < sizeof(struct audit_status))
			return -EINVAL;
		status_get   = (struct audit_status *)data;
		if (status_get->mask & AUDIT_STATUS_ENABLED) {
			err = audit_set_enabled(status_get->enabled, loginuid);
			if (err < 0) return err;
		}
		if (status_get->mask & AUDIT_STATUS_FAILURE) {
			err = audit_set_failure(status_get->failure, loginuid);
			if (err < 0) return err;
		}
		if (status_get->mask & AUDIT_STATUS_PID) {
			int old   = audit_pid;
			audit_pid = status_get->pid;
			audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
				"audit_pid=%d old=%d by auid=%u",
				  audit_pid, old, loginuid);
		}
		if (status_get->mask & AUDIT_STATUS_RATE_LIMIT)
			audit_set_rate_limit(status_get->rate_limit, loginuid);
		if (status_get->mask & AUDIT_STATUS_BACKLOG_LIMIT)
			audit_set_backlog_limit(status_get->backlog_limit,
							loginuid);
		break;
	case AUDIT_USER:
	case AUDIT_FIRST_USER_MSG...AUDIT_LAST_USER_MSG:
		if (!audit_enabled && msg_type != AUDIT_USER_AVC)
			return 0;

		err = audit_filter_user(&NETLINK_CB(skb), msg_type);
		if (err == 1) {
			err = 0;
			ab = audit_log_start(NULL, GFP_KERNEL, msg_type);
			if (ab) {
				audit_log_format(ab,
						 "user pid=%d uid=%u auid=%u msg='%.1024s'",
						 pid, uid, loginuid, (char *)data);
				audit_set_pid(ab, pid);
				audit_log_end(ab);
			}
		}
		break;
	case AUDIT_ADD:
	case AUDIT_DEL:
		if (nlh->nlmsg_len < sizeof(struct audit_rule))
			return -EINVAL;
		/* fallthrough */
	case AUDIT_LIST:
		err = audit_receive_filter(nlh->nlmsg_type, NETLINK_CB(skb).pid,
					   uid, seq, data, loginuid);
		break;
	case AUDIT_SIGNAL_INFO:
		sig_data.uid = audit_sig_uid;
		sig_data.pid = audit_sig_pid;
		audit_send_reply(NETLINK_CB(skb).pid, seq, AUDIT_SIGNAL_INFO, 
				0, 0, &sig_data, sizeof(sig_data));
		break;
	default:
		err = -EINVAL;
		break;
	}

	return err < 0 ? err : 0;
}
Example #4
0
static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
{
	u32			uid, pid, seq, sid;
	void			*data;
	struct audit_status	*status_get, status_set;
	int			err;
	struct audit_buffer	*ab;
	u16			msg_type = nlh->nlmsg_type;
	uid_t			loginuid; /* loginuid of sender */
	struct audit_sig_info   *sig_data;
	char			*ctx;
	u32			len;

	err = audit_netlink_ok(skb, msg_type);
	if (err)
		return err;

	/* As soon as there's any sign of userspace auditd,
	 * start kauditd to talk to it */
	if (!kauditd_task)
		kauditd_task = kthread_run(kauditd_thread, NULL, "kauditd");
	if (IS_ERR(kauditd_task)) {
		err = PTR_ERR(kauditd_task);
		kauditd_task = NULL;
		return err;
	}

	pid  = NETLINK_CREDS(skb)->pid;
	uid  = NETLINK_CREDS(skb)->uid;
	loginuid = NETLINK_CB(skb).loginuid;
	sid  = NETLINK_CB(skb).sid;
	seq  = nlh->nlmsg_seq;
	data = NLMSG_DATA(nlh);

	switch (msg_type) {
	case AUDIT_GET:
		status_set.enabled	 = audit_enabled;
		status_set.failure	 = audit_failure;
		status_set.pid		 = audit_pid;
		status_set.rate_limit	 = audit_rate_limit;
		status_set.backlog_limit = audit_backlog_limit;
		status_set.lost		 = atomic_read(&audit_lost);
		status_set.backlog	 = skb_queue_len(&audit_skb_queue);
		audit_send_reply(NETLINK_CB(skb).pid, seq, AUDIT_GET, 0, 0,
				 &status_set, sizeof(status_set));
		break;
	case AUDIT_SET:
		if (nlh->nlmsg_len < sizeof(struct audit_status))
			return -EINVAL;
		status_get   = (struct audit_status *)data;
		if (status_get->mask & AUDIT_STATUS_ENABLED) {
			err = audit_set_enabled(status_get->enabled,
							loginuid, sid);
			if (err < 0) return err;
		}
		if (status_get->mask & AUDIT_STATUS_FAILURE) {
			err = audit_set_failure(status_get->failure,
							 loginuid, sid);
			if (err < 0) return err;
		}
		if (status_get->mask & AUDIT_STATUS_PID) {
			int old   = audit_pid;
			if (sid) {
				if ((err = selinux_sid_to_string(
						sid, &ctx, &len)))
					return err;
				else
					audit_log(NULL, GFP_KERNEL,
						AUDIT_CONFIG_CHANGE,
						"audit_pid=%d old=%d by auid=%u subj=%s",
						status_get->pid, old,
						loginuid, ctx);
				kfree(ctx);
			} else
				audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
					"audit_pid=%d old=%d by auid=%u",
					  status_get->pid, old, loginuid);
			audit_pid = status_get->pid;
		}
		if (status_get->mask & AUDIT_STATUS_RATE_LIMIT)
			err = audit_set_rate_limit(status_get->rate_limit,
							 loginuid, sid);
		if (status_get->mask & AUDIT_STATUS_BACKLOG_LIMIT)
			err = audit_set_backlog_limit(status_get->backlog_limit,
							loginuid, sid);
		break;
	case AUDIT_USER:
	case AUDIT_FIRST_USER_MSG...AUDIT_LAST_USER_MSG:
	case AUDIT_FIRST_USER_MSG2...AUDIT_LAST_USER_MSG2:
		if (!audit_enabled && msg_type != AUDIT_USER_AVC)
			return 0;

		err = audit_filter_user(&NETLINK_CB(skb), msg_type);
		if (err == 1) {
			err = 0;
			ab = audit_log_start(NULL, GFP_KERNEL, msg_type);
			if (ab) {
				audit_log_format(ab,
						 "user pid=%d uid=%u auid=%u",
						 pid, uid, loginuid);
				if (sid) {
					if (selinux_sid_to_string(
							sid, &ctx, &len)) {
						audit_log_format(ab, 
							" ssid=%u", sid);
						/* Maybe call audit_panic? */
					} else
						audit_log_format(ab, 
							" subj=%s", ctx);
					kfree(ctx);
				}
				audit_log_format(ab, " msg='%.1024s'",
					 (char *)data);
				audit_set_pid(ab, pid);
				audit_log_end(ab);
			}
		}
		break;
	case AUDIT_ADD:
	case AUDIT_DEL:
		if (nlmsg_len(nlh) < sizeof(struct audit_rule))
			return -EINVAL;
		if (audit_enabled == 2) {
			ab = audit_log_start(NULL, GFP_KERNEL,
					AUDIT_CONFIG_CHANGE);
			if (ab) {
				audit_log_format(ab,
						 "pid=%d uid=%u auid=%u",
						 pid, uid, loginuid);
				if (sid) {
					if (selinux_sid_to_string(
							sid, &ctx, &len)) {
						audit_log_format(ab,
							" ssid=%u", sid);
						/* Maybe call audit_panic? */
					} else
						audit_log_format(ab,
							" subj=%s", ctx);
					kfree(ctx);
				}
				audit_log_format(ab, " audit_enabled=%d res=0",
					audit_enabled);
				audit_log_end(ab);
			}
			return -EPERM;
		}
		/* fallthrough */
	case AUDIT_LIST:
		err = audit_receive_filter(nlh->nlmsg_type, NETLINK_CB(skb).pid,
					   uid, seq, data, nlmsg_len(nlh),
					   loginuid, sid);
		break;
	case AUDIT_ADD_RULE:
	case AUDIT_DEL_RULE:
		if (nlmsg_len(nlh) < sizeof(struct audit_rule_data))
			return -EINVAL;
		if (audit_enabled == 2) {
			ab = audit_log_start(NULL, GFP_KERNEL,
					AUDIT_CONFIG_CHANGE);
			if (ab) {
				audit_log_format(ab,
						 "pid=%d uid=%u auid=%u",
						 pid, uid, loginuid);
				if (sid) {
					if (selinux_sid_to_string(
							sid, &ctx, &len)) {
						audit_log_format(ab,
							" ssid=%u", sid);
						/* Maybe call audit_panic? */
					} else
						audit_log_format(ab,
							" subj=%s", ctx);
					kfree(ctx);
				}
				audit_log_format(ab, " audit_enabled=%d res=0",
					audit_enabled);
				audit_log_end(ab);
			}
			return -EPERM;
		}
		/* fallthrough */
	case AUDIT_LIST_RULES:
		err = audit_receive_filter(nlh->nlmsg_type, NETLINK_CB(skb).pid,
					   uid, seq, data, nlmsg_len(nlh),
					   loginuid, sid);
		break;
	case AUDIT_SIGNAL_INFO:
		err = selinux_sid_to_string(audit_sig_sid, &ctx, &len);
		if (err)
			return err;
		sig_data = kmalloc(sizeof(*sig_data) + len, GFP_KERNEL);
		if (!sig_data) {
			kfree(ctx);
			return -ENOMEM;
		}
		sig_data->uid = audit_sig_uid;
		sig_data->pid = audit_sig_pid;
		memcpy(sig_data->ctx, ctx, len);
		kfree(ctx);
		audit_send_reply(NETLINK_CB(skb).pid, seq, AUDIT_SIGNAL_INFO, 
				0, 0, sig_data, sizeof(*sig_data) + len);
		kfree(sig_data);
		break;
	default:
		err = -EINVAL;
		break;
	}

	return err < 0 ? err : 0;
}