AUDIT: Add message types to audit records

This patch adds more messages types to the audit subsystem so that audit 
analysis is quicker, intuitive, and more useful.

Signed-off-by: Steve Grubb <sgrubb@redhat.com>
---
I forgot one type in the big patch. I need to add one for user space 
originating SE Linux avc messages. This is used by dbus and nscd.

-Steve
---
Updated to 2.6.12-rc4-mm1.
-dwmw2

Signed-off-by: David Woodhouse <dwmw2@infradead.org>
diff --git a/kernel/audit.c b/kernel/audit.c
index 1871645..4e940c0 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -140,6 +140,12 @@
 	struct audit_context *ctx;	/* NULL or associated context */
 };
 
+static void audit_set_pid(struct audit_buffer *ab, pid_t pid)
+{
+	struct nlmsghdr *nlh = (struct nlmsghdr *)ab->skb->data;
+	nlh->nlmsg_pid = pid;
+}
+
 struct audit_entry {
 	struct list_head  list;
 	struct audit_rule rule;
@@ -233,7 +239,8 @@
 {
 	int old		 = audit_rate_limit;
 	audit_rate_limit = limit;
-	audit_log(NULL, "audit_rate_limit=%d old=%d by auid %u",
+	audit_log(NULL, AUDIT_CONFIG_CHANGE, 
+			"audit_rate_limit=%d old=%d by auid %u",
 			audit_rate_limit, old, loginuid);
 	return old;
 }
@@ -242,7 +249,8 @@
 {
 	int old		 = audit_backlog_limit;
 	audit_backlog_limit = limit;
-	audit_log(NULL, "audit_backlog_limit=%d old=%d by auid %u",
+	audit_log(NULL, AUDIT_CONFIG_CHANGE,
+			"audit_backlog_limit=%d old=%d by auid %u",
 			audit_backlog_limit, old, loginuid);
 	return old;
 }
@@ -253,8 +261,9 @@
 	if (state != 0 && state != 1)
 		return -EINVAL;
 	audit_enabled = state;
-	audit_log(NULL, "audit_enabled=%d old=%d by auid %u",
-		  audit_enabled, old, loginuid);
+	audit_log(NULL, AUDIT_CONFIG_CHANGE,
+			"audit_enabled=%d old=%d by auid %u",
+			audit_enabled, old, loginuid);
 	return old;
 }
 
@@ -266,8 +275,9 @@
 	    && state != AUDIT_FAIL_PANIC)
 		return -EINVAL;
 	audit_failure = state;
-	audit_log(NULL, "audit_failure=%d old=%d by auid %u",
-		  audit_failure, old, loginuid);
+	audit_log(NULL, AUDIT_CONFIG_CHANGE,
+			"audit_failure=%d old=%d by auid %u",
+			audit_failure, old, loginuid);
 	return old;
 }
 
@@ -316,6 +326,14 @@
 			err = -EPERM;
 		break;
 	case AUDIT_USER:
+	case AUDIT_USER_AUTH:
+	case AUDIT_USER_ACCT:
+	case AUDIT_USER_MGMT:
+	case AUDIT_CRED_ACQ:
+	case AUDIT_CRED_DISP:
+	case AUDIT_USER_START:
+	case AUDIT_USER_END:
+	case AUDIT_USER_AVC:
 		if (!cap_raised(eff_cap, CAP_AUDIT_WRITE))
 			err = -EPERM;
 		break;
@@ -332,6 +350,7 @@
 	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;
@@ -373,7 +392,8 @@
 		if (status_get->mask & AUDIT_STATUS_PID) {
 			int old   = audit_pid;
 			audit_pid = status_get->pid;
-			audit_log(NULL, "audit_pid=%d old=%d by auid %u",
+			audit_log(NULL, AUDIT_CONFIG_CHANGE,
+				"audit_pid=%d old=%d by auid %u",
 				  audit_pid, old, loginuid);
 		}
 		if (status_get->mask & AUDIT_STATUS_RATE_LIMIT)
@@ -383,13 +403,26 @@
 							loginuid);
 		break;
 	case AUDIT_USER:
-		audit_log_type(NULL, AUDIT_USER, pid,
+	case AUDIT_USER_AUTH:
+	case AUDIT_USER_ACCT:
+	case AUDIT_USER_MGMT:
+	case AUDIT_CRED_ACQ:
+	case AUDIT_CRED_DISP:
+	case AUDIT_USER_START:
+	case AUDIT_USER_END:
+	case AUDIT_USER_AVC:
+		ab = audit_log_start(NULL, msg_type);
+		if (!ab)
+			break;	/* audit_panic has been called */
+		audit_log_format(ab,
 				 "user pid=%d uid=%d length=%d loginuid=%u"
 				 " msg='%.1024s'",
 				 pid, uid,
 				 (int)(nlh->nlmsg_len
 				       - ((char *)data - (char *)nlh)),
 				 loginuid, (char *)data);
+		audit_set_pid(ab, pid);
+		audit_log_end(ab);
 		break;
 	case AUDIT_ADD:
 	case AUDIT_DEL:
@@ -504,7 +537,7 @@
 
 	audit_initialized = 1;
 	audit_enabled = audit_default;
-	audit_log(NULL, "initialized");
+	audit_log(NULL, AUDIT_KERNEL, "initialized");
 	return 0;
 }
 __initcall(audit_init);
@@ -541,10 +574,12 @@
 	spin_unlock_irqrestore(&audit_freelist_lock, flags);
 }
 
-static struct audit_buffer * audit_buffer_alloc(int gfp_mask)
+static struct audit_buffer * audit_buffer_alloc(struct audit_context *ctx,
+						int gfp_mask, int type)
 {
 	unsigned long flags;
 	struct audit_buffer *ab = NULL;
+	struct nlmsghdr *nlh;
 
 	spin_lock_irqsave(&audit_freelist_lock, flags);
 	if (!list_empty(&audit_freelist)) {
@@ -566,6 +601,12 @@
 	if (!ab->skb)
 		goto err;
 
+	ab->ctx   = ctx;
+	nlh = (struct nlmsghdr *)skb_put(ab->skb, NLMSG_SPACE(0));
+	nlh->nlmsg_type = type;
+	nlh->nlmsg_flags = 0;
+	nlh->nlmsg_pid = 0;
+	nlh->nlmsg_seq = 0;
 	return ab;
 err:
 	audit_buffer_free(ab);
@@ -578,12 +619,11 @@
  * syscall, then the syscall is marked as auditable and an audit record
  * will be written at syscall exit.  If there is no associated task, tsk
  * should be NULL. */
-struct audit_buffer *audit_log_start(struct audit_context *ctx, int type, int pid)
+struct audit_buffer *audit_log_start(struct audit_context *ctx, int type)
 {
 	struct audit_buffer	*ab	= NULL;
 	struct timespec		t;
 	unsigned int		serial;
-	struct nlmsghdr *nlh;
 
 	if (!audit_initialized)
 		return NULL;
@@ -600,19 +640,12 @@
 		return NULL;
 	}
 
-	ab = audit_buffer_alloc(GFP_ATOMIC);
+	ab = audit_buffer_alloc(ctx, GFP_ATOMIC, type);
 	if (!ab) {
 		audit_log_lost("out of memory in audit_log_start");
 		return NULL;
 	}
 
-	ab->ctx   = ctx;
-	nlh = (struct nlmsghdr *)skb_put(ab->skb, NLMSG_SPACE(0));
-	nlh->nlmsg_type = type;
-	nlh->nlmsg_flags = 0;
-	nlh->nlmsg_pid = pid;
-	nlh->nlmsg_seq = 0;
-
 	if (!audit_get_stamp(ab->ctx, &t, &serial)) {
 		t = CURRENT_TIME;
 		serial = 0;
@@ -809,13 +842,12 @@
 /* Log an audit record.  This is a convenience function that calls
  * audit_log_start, audit_log_vformat, and audit_log_end.  It may be
  * called in any context. */
-void audit_log_type(struct audit_context *ctx, int type, int pid,
-		    const char *fmt, ...)
+void audit_log(struct audit_context *ctx, int type, const char *fmt, ...)
 {
 	struct audit_buffer *ab;
 	va_list args;
 
-	ab = audit_log_start(ctx, type, pid);
+	ab = audit_log_start(ctx, type);
 	if (ab) {
 		va_start(args, fmt);
 		audit_log_vformat(ab, fmt, args);
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index d089263..1b7c91f 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -286,7 +286,8 @@
 			err = audit_add_rule(entry, &audit_entlist);
 		if (!err && (flags & AUDIT_AT_EXIT))
 			err = audit_add_rule(entry, &audit_extlist);
-		audit_log(NULL, "auid %u added an audit rule\n", loginuid);
+		audit_log(NULL, AUDIT_CONFIG_CHANGE, 
+				"auid %u added an audit rule\n", loginuid);
 		break;
 	case AUDIT_DEL:
 		flags =((struct audit_rule *)data)->flags;
@@ -296,7 +297,8 @@
 			err = audit_del_rule(data, &audit_entlist);
 		if (!err && (flags & AUDIT_AT_EXIT))
 			err = audit_del_rule(data, &audit_extlist);
-		audit_log(NULL, "auid %u removed an audit rule\n", loginuid);
+		audit_log(NULL, AUDIT_CONFIG_CHANGE,
+				"auid %u removed an audit rule\n", loginuid);
 		break;
 	default:
 		return -EINVAL;
@@ -648,7 +650,7 @@
 	int i;
 	struct audit_buffer *ab;
 
-	ab = audit_log_start(context, AUDIT_KERNEL, 0);
+	ab = audit_log_start(context, AUDIT_SYSCALL);
 	if (!ab)
 		return;		/* audit_panic has been called */
 	audit_log_format(ab, "syscall=%d", context->major);
@@ -680,28 +682,28 @@
 	while (context->aux) {
 		struct audit_aux_data *aux;
 
-		ab = audit_log_start(context, AUDIT_KERNEL, 0);
+		aux = context->aux;
+
+		ab = audit_log_start(context, aux->type);
 		if (!ab)
 			continue; /* audit_panic has been called */
 
-		aux = context->aux;
-		context->aux = aux->next;
-
-		audit_log_format(ab, "auxitem=%d", aux->type);
 		switch (aux->type) {
-		case AUDIT_AUX_IPCPERM: {
+		case AUDIT_IPC: {
 			struct audit_aux_data_ipcctl *axi = (void *)aux;
 			audit_log_format(ab, 
-					 " qbytes=%lx uid=%d gid=%d mode=%x",
+					 " qbytes=%lx iuid=%d igid=%d mode=%x",
 					 axi->qbytes, axi->uid, axi->gid, axi->mode);
 			}
 		}
 		audit_log_end(ab);
+
+		context->aux = aux->next;
 		kfree(aux);
 	}
 
 	for (i = 0; i < context->name_count; i++) {
-		ab = audit_log_start(context, AUDIT_KERNEL, 0);
+		ab = audit_log_start(context, AUDIT_PATH);
 		if (!ab)
 			continue; /* audit_panic has been called */
 		audit_log_format(ab, "item=%d", i);
@@ -711,7 +713,7 @@
 		}
 		if (context->names[i].ino != (unsigned long)-1)
 			audit_log_format(ab, " inode=%lu dev=%02x:%02x mode=%#o"
-					     " uid=%d gid=%d rdev=%02x:%02x",
+					     " ouid=%d ogid=%d rdev=%02x:%02x",
 					 context->names[i].ino,
 					 MAJOR(context->names[i].dev),
 					 MINOR(context->names[i].dev),
@@ -1008,10 +1010,16 @@
 int audit_set_loginuid(struct task_struct *task, uid_t loginuid)
 {
 	if (task->audit_context) {
-		audit_log_type(NULL, AUDIT_LOGIN, 0,
-			  "login pid=%d uid=%u old loginuid=%u new loginuid=%u",
-			  task->pid, task->uid, task->audit_context->loginuid,
-			  loginuid);
+		struct audit_buffer *ab;
+
+		ab = audit_log_start(NULL, AUDIT_LOGIN);
+		if (ab) {
+			audit_log_format(ab, "login pid=%d uid=%u "
+				"old loginuid=%u new loginuid=%u",
+				task->pid, task->uid, 
+				task->audit_context->loginuid, loginuid);
+			audit_log_end(ab);
+		}
 		task->audit_context->loginuid = loginuid;
 	}
 	return 0;
@@ -1039,7 +1047,7 @@
 	ax->gid = gid;
 	ax->mode = mode;
 
-	ax->d.type = AUDIT_AUX_IPCPERM;
+	ax->d.type = AUDIT_IPC;
 	ax->d.next = context->aux;
 	context->aux = (void *)ax;
 	return 0;