Commits

Stephen Smalley  committed 97a24f6

Sync with master auditd.

  • Participants
  • Parent commits 01ea163
  • Branches seandroid-4.2

Comments (0)

Files changed (9)

File auditd/Android.mk

 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
+# Override this in the BoardConfig.mk
+# to change the default size
+# Note: The value is in Kilobytes
+AUDITD_MAX_LOG_FILE_SIZEKB ?= 100
+
 LOCAL_SRC_FILES:= \
 	auditd.c \
-	netlink.c \
 	libaudit.c \
 	audit_log.c
 
 	libcutils \
 	libc
 
-LOCAL_MODULE_TAGS:=optional
-LOCAL_MODULE:=auditd
-
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := auditd
+LOCAL_CFLAGS := -DAUDITD_MAX_LOG_FILE_SIZEKB=$(AUDITD_MAX_LOG_FILE_SIZEKB)
 include $(BUILD_EXECUTABLE)

File auditd/README

+Auditd Daemon
+
+The audit daemon is a simplified version of its desktop
+counterpart designed to gather the audit logs from the
+audit kernel subsystem. The audit subsystem of the kernel
+includes Linux Security Modules (LSM) messages as well.
+
+To enable the audit subsystem, you must add this to your
+kernel config:
+CONFIG_AUDIT=y
+CONFIG_AUDITSYSCALL=y
+
+To enable a LSM, you must consult that LSM's documentation, the
+example below is for SELinux:
+CONFIG_SECURITY_SELINUX=y
+
+This does not include possible dependencies that may need to be
+satisfied for that particular LSM.
+
+The daemon maintains two log files audit.log and audit.old
+at /data/misc/audit/. On boot, if audit.log exists, and
+the size is greater than 0, audit.log is renamed to
+audit.old. The log file is also renamed, or rotated, when
+a threshold is hit. This threshold is hard-coded to 100KB
+but can be adjusted through the AUDITD_MAX_LOG_FILE_SIZEKB
+Makefile file variable that can be overridden in the device.mk
+
+The daemon is not included by default, and must explicitly be
+added to PRODUCT_PACKAGES. This could be set in the device.mk
+
+The daemon also has no external interfaces, but one could
+use inotify to start and build a system from this. The log
+files are owned by UID audit and readable by system. A
+system UID application could conceivably be used to consume
+these logs.
+
+Example configuration in device.mk:
+
+# 1MB Log file threshold
+AUDITD_MAX_LOG_FILE_SIZEKB := 1000
+
+PRODUCT_PACKAGES += auditd
+
+

File auditd/audit_log.c

+/*
+ * Copyright 2012, Samsung Telecommunications of America
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Written by William Roberts <w.roberts@sta.samsung.com>
+ */
+
 #include <errno.h>
 #include <fcntl.h>
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
 #include <stdint.h>
-
+#include <stdarg.h>
+#include <ctype.h>
+#include <alloca.h>
 #include <sys/klog.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 
+#define LOG_TAG "audit_log"
+#include <cutils/log.h>
+
 #include "libaudit.h"
 #include "audit_log.h"
-#include "auditd.h"
 
-#define AUDIT_LOG_MODE (S_IRUSR | S_IWUSR | S_IRGRP)
+/*
+ * Note that the flags passed to fcntl and the flags used
+ * by fopen must be compatible. For instance, specifying
+ * write only on one and read only on the other will yield
+ * strange behavior.
+ */
+/* Mode for fopen */
+#define AUDIT_LOG_FMODE "w+"
+/* mode for fchmod*/
+#define AUDIT_LOG_MODE  (S_IRUSR | S_IWUSR | S_IRGRP)
+/* flags for fcntl */
 #define AUDIT_LOG_FLAGS (O_RDWR | O_CREAT | O_SYNC)
 
-struct audit_log {
-	int fd;
-	size_t total_bytes;
-	size_t threshold;
-	char *rotatefile;
-	char *logfile;
+#define AUDIT_TYPE    "type="
+#define AUDIT_MSG     "msg="
+#define AUDIT_KEYWORD "audit("
+
+struct audit_log
+{
+    FILE *file;
+    size_t total_bytes;
+    size_t threshold;
+    char *rotatefile;
+    char *logfile;
 };
 
 /**
- * Writes data pointed by buf to audit log, appends a trailing newline.
- * @param l
- *  The log to write
- * @param buf
- *  The data to write
- * @param len
- *  The length of the data
+ * Wraps open with a fchmod to prevent umask issues from arising in
+ * permission setting as well as a fcntl to set the underlying
+ * fds mode. However, the rest of the library relies on stdio file
+ * access, so a FILE pointer is returned.
+ *
+ * You must make sure your mode and fmode are compatible
+ *
+ * @param file
+ *  File stream output
+ * @param path
+ *  The path of the log file
+ * @param flags
+ *  The flags passed to fcntl
+ * @param fmode
+ *  The mode passed to fopen
+ * @param mode
+ *  The mode passed to open and fchmod
  * @return
+ *  0 on success with *file set, or -errno on error
  */
-static int write_log(audit_log *l, const void *buf, size_t len) {
-
-	int rc = 0;
-	ssize_t bytes = 0;
-
-	/*
-	 * Ensure that the pointer offset and
-	 * number of bytes written are the same
-	 * size. Avoid char *, as on esoteric
-	 * systems that are not byte addressable
-	 * it could be defined as something else.
-	 */
-	const uint8_t *b = (uint8_t *)buf;
-
-	if(!l) {
-		rc = EINVAL;
-		goto err;
-	}
-
-	do {
-		bytes = write(l->fd, b, len);
-		if(bytes < 0 && errno != EINTR) {
-			rc = errno;
-			goto err;
-		}
-		b += bytes;
-		len -= bytes;
-		l->total_bytes += bytes;
-	} while (len > 0);
-
-
-out:
-	/*
-	 * Always attempt to write a newline, but ignore
-	 * any errors as it could be a cascading effect
-	 * from above.
-	 */
-	bytes = write(l->fd, "\n", 1);
-	l->total_bytes += (bytes > 0) ? bytes : 0;
-
-	/*
-	 * Always attempt to rotate, even in the
-	 * face of errors above
-	 */
-	if(l->total_bytes > l->threshold) {
-		rc = audit_log_rotate(l);
-	}
-
-	return rc;
+static int open_log(FILE **file, const char *path, int flags, const char *fmode, mode_t mode)
+{
+    int fd;
+    int rc;
+
+    if(!file) {
+        return -EINVAL;
+    }
+
+    *file = fopen(path, fmode);
+    if(!*file) {
+        rc = -errno;
+        SLOGE("Could not open audit log file %s : %s", path, strerror(errno));
+        return rc;
+    }
+
+    rc = setvbuf(*file, NULL, _IONBF, 0);
+    if (rc != 0) {
+        rc = -errno;
+        SLOGE("Could not setvbuf the log file");
+        goto err;
+    }
+
+    fd = fileno(*file);
+    rc = fchmod(fd, mode);
+    if (rc < 0) {
+        rc = -errno;
+        SLOGE("Could not fchmod the log file");
+        goto err;
+    }
+
+    rc = fcntl(fd, F_SETFD, flags);
+    if (rc < 0) {
+        rc = -errno;
+        SLOGE("Could not fcntl the log file");
+        goto err;
+    }
+
+    return 0;
 
 err:
-	ERROR("Error in function: %s, line: %d, error: %s\n",
-		__FUNCTION__, __LINE__, strerror(rc));
-	goto out;
+    fclose(*file);
+    return rc;
 }
 
-audit_log *audit_log_open(const char *logfile, const char *rotatefile, size_t threshold) {
-
-	int fd = -1;
-	audit_log *l = NULL;
-	struct stat log_file_stats;
-
-	if (stat(logfile, &log_file_stats) < 0) {
-		if (errno != ENOENT) {
-			ERROR("Could not stat %s: %s\n",
-				logfile, strerror(errno));
-			goto err;
-		}
-	}
-	/* The existing log had data */
-	else if (log_file_stats.st_size != 0){
-		if (rename(logfile, rotatefile) < 0) {
-			ERROR("Could not rename %s to %s: %s\n",
-				logfile, rotatefile, strerror(errno));
-			goto err;
-		}
-	}
-
-	/* Open the output logfile */
-	fd = open(logfile, AUDIT_LOG_FLAGS, AUDIT_LOG_MODE);
-	if (fd < 0) {
-		ERROR("Could not open %s: %s\n",
-			logfile, strerror(errno));
-		goto err;
-	}
-	fchmod(fd, AUDIT_LOG_MODE);
-
-	l = calloc(sizeof(struct audit_log), 1);
-	if (!l) {
-		goto err;
-	}
-	l->rotatefile = strdup(rotatefile);
-	if (!l->rotatefile) {
-		goto err;
-	}
-
-	l->logfile = strdup(logfile);
-	if (!l->logfile) {
-		goto err;
-	}
-	l->fd = fd;
-	l->threshold = threshold;
-
-out:
-	return l;
+audit_log *audit_log_open(const char *logfile, const char *rotatefile, size_t threshold)
+{
+    int rc;
+    audit_log *l = NULL;
+    struct stat log_file_stats;
+
+    rc = stat(logfile, &log_file_stats);
+    if (rc < 0) {
+        if(errno != ENOENT) {
+            SLOGE("Could not stat audit logfile %s: %s", logfile, strerror(errno));
+            return NULL;
+        }
+        else {
+            SLOGI("Previous audit logfile not detected");
+        }
+    }
+
+    /* The existing log had data */
+    if (rc == 0 && log_file_stats.st_size >= 0) {
+        rc = rename(logfile, rotatefile);
+        if (rc < 0) {
+            SLOGE("Could not rename %s to %s: %s", logfile, rotatefile, strerror(errno));
+            return NULL;
+        }
+        SLOGI("Previous audit logfile detected, rotating\n");
+    }
+
+    l = calloc(sizeof(struct audit_log), 1);
+    if (!l) {
+        SLOGE("Out of memory while allocating audit log");
+        return NULL;
+    }
+
+    /* Open the output logfile */
+    rc = open_log(&(l->file), logfile, AUDIT_LOG_FLAGS, AUDIT_LOG_FMODE, AUDIT_LOG_MODE);
+    if (rc < 0) {
+        /* Error message handled by open_log() */
+        return NULL;
+    }
+
+    l->rotatefile = strdup(rotatefile);
+    if (!l->rotatefile) {
+        SLOGE("Out of memory while duplicating rotatefile string");
+        goto err;
+    }
+
+    l->logfile = strdup(logfile);
+    if (!l->logfile) {
+        SLOGE("Out of memory while duplicating logfile string");
+        goto err;
+    }
+
+    l->threshold = threshold;
+
+    return l;
 
 err:
-	audit_log_close(l);
-	l = NULL;
-	goto out;
+    audit_log_close(l);
+    return NULL;
 }
 
-int audit_log_write_str(audit_log *l, const char *str) {
-	return write_log(l, str, strlen(str));
-}
+int audit_log_write(audit_log *l, const char *fmt, ...)
+{
+    int rc;
+    va_list args;
 
-int audit_log_write(audit_log *l, const struct audit_reply *reply) {
-	return write_log(l, reply->msg.data, reply->len);
-}
+    if (l == NULL || fmt == NULL) {
+        return -EINVAL;
+    }
+
+    va_start(args, fmt);
+    rc = vfprintf(l->file, fmt, args);
+    va_end(args);
 
-int audit_log_rotate(audit_log *l) {
-	int rc = 0;
-	if(!l) {
-		rc = EINVAL;
-		goto err;
-	}
-
-	rc = rename(l->logfile, l->rotatefile);
-	if (rc < 0) {
-		rc = errno;
-		goto err;
-	}
-
-	close(l->fd);
-	l->total_bytes = 0;
-
-	l->fd = open(l->logfile, AUDIT_LOG_FLAGS, AUDIT_LOG_MODE);
-	if(l->fd < 0) {
-		rc = errno;
-		goto err;
-	}
-	fchmod(l->fd, AUDIT_LOG_MODE);
+    if(rc < 0) {
+        SLOGE("Error writing to log file");
+        clearerr(l->file);
+        rc = -EINVAL;
+        goto out;
+    }
+
+    l->total_bytes += rc;
 
 out:
-	return rc;
-err:
-	goto out;
+    if(l->total_bytes > l->threshold) {
+        /* audit_log_rotate() handles error message */
+        rc = audit_log_rotate(l);
+    }
+
+    return rc;
+}
+
+int audit_log_rotate(audit_log *l)
+{
+    FILE *file;
+    int rc = 0;
+
+    if (!l) {
+        return -EINVAL;
+    }
+
+    rc = rename(l->logfile, l->rotatefile);
+    if (rc < 0) {
+        rc = -errno;
+        SLOGE("Could not rename audit log file \"%s\" to \"%s\", error: %s",
+                l->logfile, l->rotatefile, strerror(errno));
+        return rc;
+    }
+
+    rc = open_log(&file, l->logfile, AUDIT_LOG_FLAGS, AUDIT_LOG_FMODE, AUDIT_LOG_MODE);
+    if (rc < 0) {
+        /* Error message handled by open_log() */
+        return rc;
+    }
+
+    fclose(l->file);
+    l->total_bytes = 0;
+    l->file = file;
+
+    return 0;
 }
 
-void audit_log_close(audit_log *l) {
-	if(l) {
-		if(l->logfile) {
-			free(l->logfile);
-		}
-		if(l->rotatefile) {
-			free(l->rotatefile);
-		}
-		if(l->fd >= 0) {
-			close(l->fd);
-		}
-		free(l);
-		l = NULL;
-	}
-	return;
+void audit_log_close(audit_log *l)
+{
+    if (!l) {
+        return;
+    }
+
+    free(l->logfile);
+    free(l->rotatefile);
+    if (l->file) {
+        fclose(l->file);
+    }
+    free(l);
+    return;
 }
 
-int audit_log_put_kmsg(audit_log *l) {
-
-	char *tok;
-
-	int rc = 0;
-	char *buf = NULL;
-	int len = klogctl(KLOG_SIZE_BUFFER, NULL, 0);
-
-	if (len > 0) {
-		len++;
-		buf = malloc(len * sizeof(*buf));
-		if (!buf) {
-			ERROR("Out of memory\n");
-			rc = ENOMEM;
-			goto err;
-		}
-	}
-	else if(len < 0) {
-		ERROR("Could not read logs: %s\n",
-				strerror(errno));
-		rc = errno;
-		goto err;
-	}
-
-	rc = klogctl(KLOG_READ_ALL, buf, len);
-	if(rc < 0) {
-		ERROR("Could not read logs: %s\n",
-				strerror(errno));
-		rc = errno;
-		goto err;
-	}
-
-	buf[len-1] = '\0';
-	tok = buf;
-
-	while((tok = strtok(tok, "\r\n"))) {
-		if(strstr(tok, " audit(")) {
-			audit_log_write_str(l, tok);
-		}
-		tok = NULL;
-	}
+int audit_log_put_kmsg(audit_log *l)
+{
+    char *tok;
+    char *audit;
+    char *type;
+    int rc = 0;
+    char *buf = NULL;
+    int len = klogctl(KLOG_SIZE_BUFFER, NULL, 0);
+
+    /* No data to read */
+    if (len == 0) {
+        SLOGI("Empty kmsg");
+        return 0;
+    }
+
+    /* Error */
+    if (len < 0) {
+        rc = -errno;
+        SLOGE("Could not read kernel log length: %s", strerror(errno));
+        return rc;
+    }
+
+    /* Data to read */
+    len++;
+    buf = malloc(len * sizeof(*buf));
+    if (!buf) {
+        SLOGE("Out of memory wile allocating kmsg buffer");
+        return -ENOMEM;
+    }
+
+    rc = klogctl(KLOG_READ_ALL, buf, len);
+    if (rc < 0) {
+        rc = -errno;
+        SLOGE("Could not read kernel log data: %s", strerror(errno));
+        goto err;
+    }
+
+    buf[len - 1] = '\0';
+    tok = buf;
+
+    while ((tok = strtok(tok, "\r\n"))) {
+
+        /* Only print audit messages The SPACE is important!! as we want the
+         * audit pointer pointing to a space and not the beginning of the message.
+         * This helps ensure that we don't erroneously going down the wrong path when
+         * parsing this data.
+         * XXX Should we include the space in the AUDIT_KEYWORD macro?
+         */
+        audit = strstr(tok, " "AUDIT_KEYWORD);
+        if (audit) {
+
+            /* Place a null terminator at the space, and advance the pointer past it */
+            *audit++ = '\0';
+
+            /* If it has type field, print that than msg=<rest> */
+            type = strstr(tok, AUDIT_TYPE);
+            if (type) {
+
+                /*
+                 * The type should be the the left of the space we replaced with a
+                 * null terminator
+                 *
+                 * type is pointing to type=1400\0 and audit is pointing to audit(....\0
+                 */
+                rc = audit_log_write(l, "%s msg=%s\n", type, audit);
+                if(rc < 0) {
+                    /* audit_log_write handles error message */
+                    goto err;
+                }
+            }
+            /* It contined the AUDIT_KEWORD but was not formatted as expected, just dump it */
+            else {
+                SLOGW("Improperly formatted kernel audit message, dumping as is");
+                rc = audit_log_write(l, "%s\n", audit);
+                if(rc < 0) {
+                    /* audit_log_write handles error message */
+                    goto err;
+                }
+            }
+        }
+        tok = NULL;
+    }
 
 err:
-	if (buf) {
-		free(buf);
-	}
-
-	return 0;
+    free(buf);
+    return rc;
 }

File auditd/audit_log.h

  *  The threshold, in bytes, the log file should grow to
  *  until rotation.
  * @return
- *  A valid handle to the audit_log.
+ *  A valid handle to the audit_log or NULL on failure.
  */
 extern audit_log *audit_log_open(const char *logfile, const char *rotatefile, size_t threshold);
 
 /**
- * Appends an audit reposnse to the audit log, and rotates the log if threshold is
- * passed. Note, it always finishes a message even if it is past threshold. Also
- * always appends a newline to the end of the message.
+ * Writes a formatted message to the audit log
  * @param l
- *  The audit log to use
- * @param reply
- *  The response to write
+ *  The log to write too
+ * @param fmt
+ *  The fmt specifier as passed to fprintf/printf family of functions
  * @return
- *  0 on success
- */
-extern int audit_log_write(audit_log *l, const struct audit_reply *reply);
-
-/**
- * Appends a string to the audit log, appending a newline, and rotating
- * the logs if needed.
- * @param l
- *  The audit log to append too.
- * @param str
- *  The string to append to the log.
- * @return
- *  0 on success
+ *  0 on success or -errno on error
+ *
  */
-extern int audit_log_write_str(audit_log *l, const char *str);
+extern int audit_log_write(audit_log *l, const char *fmt, ...);
 
 /**
  * Forces a rotation of the audit log.
  * @param l
  *  The log file to use
  * @return
- *  0 on success
+ *  0 on success, -errno on failure.
  */
 extern int audit_log_rotate(audit_log *l);
 
 /**
  * Closes the audit log file.
  * @param l
- *  The log file to close, NULL's the pointer.
+ *  The log file to close.
  */
 extern void audit_log_close(audit_log *l);
 
 /**
- * Searches once through kmesg for type=1400
+ * Searches once through kmsg for type=1400
  * kernel messages and logs them to the audit log
  * @param l
- * 	The log to append too
+ *  The log to append too
  * @return
- *  0 on success
+ *  0 on success, -errno on failure.
  */
 extern int audit_log_put_kmsg(audit_log *l);
 

File auditd/auditd.c

  * Written by William Roberts <w.roberts@sta.samsung.com>
  */
 
+#define LOG_TAG "auditd"
+
 #include <stdio.h>
 #include <stdlib.h>
 
 #include <syslog.h>
 #include <unistd.h>
 
+#include <sys/capability.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 
+#include <cutils/log.h>
 #include <cutils/klog.h>
+
+#include <cutils/log.h>
 #include <private/android_filesystem_config.h>
 
 #include <linux/capability.h>
 #include <linux/prctl.h>
 
-#include "auditd.h"
 #include "libaudit.h"
 #include "audit_log.h"
 
  *   1. Add a socket interface for sending events
  */
 
-#define LOG_DIR "/data/misc/audit"
-#define LOG_FILE LOG_DIR "/audit.log"
-#define OLD_LOG_FILE LOG_DIR "/audit.old"
+#ifndef AUDITD_MAX_LOG_FILE_SIZEKB
+#error "AUDITD_MAX_LOG_FILE_SIZEKB not defined by makefile!"
+#endif
+
+#define AUDITD_LOG_DIR "/data/misc/audit"
+#define AUDITD_LOG_FILE AUDITD_LOG_DIR "/audit.log"
+#define AUDITD_OLD_LOG_FILE AUDITD_LOG_DIR "/audit.old"
 
-#define MAX_LOG_FILE_SIZE (1024 * 100)
+#define AUDITD_MAX_LOG_FILE_SIZE (1024 * AUDITD_MAX_LOG_FILE_SIZEKB)
 
 static volatile int quit = 0;
 
-static void signal_handler(int sig) {
-	switch (sig) {
-		case SIGINT:
-			quit = 1;
-		break;
-	}
-	return;
+static void signal_handler(int sig)
+{
+    switch (sig) {
+    case SIGINT:
+    case SIGTERM:
+        quit = 1;
+        break;
+    }
+    return;
 }
 
-static void usage(char *cmd) {
-	printf("%s - log audit events from the kernel\n"
-			"OPTIONS\n"
-			"-k - search dmesg on startup for audit events\n"
-			"\n",
-			cmd);
+static void usage(char *cmd)
+{
+    printf("%s - log audit events from the kernel\n"
+            "OPTIONS\n"
+            "-k - search dmesg on startup for audit events\n"
+            "\n", cmd);
 }
 
 #define RAISE(ary, c) ary[CAP_TO_INDEX(c)].permitted |= CAP_TO_MASK(c);
 
-static void drop_privileges_or_die(void) {
-	struct __user_cap_header_struct capheader;
-	struct __user_cap_data_struct capdata[2];
-
-	if (prctl(PR_SET_KEEPCAPS, 1) < 0) {
-		ERROR("Failed on prctl KEEPCAPS: %s\n", strerror(errno));
-		exit(1);
-	}
-
-	if (setgid(AID_AUDIT) < 0) {
-		ERROR("Failed on setgid: %s\n", strerror(errno));
-		exit(1);
-	}
-
-	if (setuid(AID_AUDIT) < 0) {
-		ERROR("Failed on setuid: %s\n", strerror(errno));
-		exit(1);
-	}
-
-	memset(&capheader, 0, sizeof(capheader));
-	memset(&capdata, 0, sizeof(capdata));
-	capheader.version = _LINUX_CAPABILITY_VERSION_3;
-	capheader.pid = 0;
-
-	RAISE(capdata, CAP_AUDIT_CONTROL);
-	RAISE(capdata, CAP_SYSLOG);
-
-	capdata[0].effective = capdata[0].permitted;
-	capdata[1].effective = capdata[1].permitted;
-	capdata[0].inheritable = 0;
-	capdata[1].inheritable = 0;
-
-	if (capset(&capheader, &capdata[0]) < 0) {
-		ERROR("Failed on capset: %s\n", strerror(errno));
-		exit(1);
-	}
+static void drop_privileges_or_die(void)
+{
+
+    struct __user_cap_header_struct capheader;
+    struct __user_cap_data_struct capdata[2];
+
+    if (prctl(PR_SET_KEEPCAPS, 1) < 0) {
+        SLOGE("Failed on prctl KEEPCAPS: %s", strerror(errno));
+        exit(1);
+    }
+
+    if (setgid(AID_AUDIT) < 0) {
+        SLOGE("Failed on setgid: %s", strerror(errno));
+        exit(1);
+    }
+
+    if (setuid(AID_AUDIT) < 0) {
+        SLOGE("Failed on setuid: %s", strerror(errno));
+        exit(1);
+    }
+
+    memset(&capheader, 0, sizeof(capheader));
+    memset(&capdata, 0, sizeof(capdata));
+    capheader.version = _LINUX_CAPABILITY_VERSION_3;
+    capheader.pid = 0;
+
+    RAISE(capdata, CAP_AUDIT_CONTROL);
+    RAISE(capdata, CAP_SYSLOG);
+
+    capdata[0].effective = capdata[0].permitted;
+    capdata[1].effective = capdata[1].permitted;
+    capdata[0].inheritable = 0;
+    capdata[1].inheritable = 0;
+
+    if (capset(&capheader, &capdata[0]) < 0) {
+        SLOGE("Failed on capset: %s", strerror(errno));
+        exit(1);
+    }
 }
 
-int main(int argc, char *argv[]) {
-
-	int c;
-
-	struct audit_reply rep;
-	struct sigaction action;
-
-	int rc;
-	int audit_fd = -1;
-	int check_kernel_log = 0;
-
-	audit_log *l = NULL;
-	ssize_t total_bytes = 0;
-	struct pollfd pfds;
-
-	INFO("auditd:  starting up\n");
-
-	drop_privileges_or_die();
-
-	/* register the signal handler */
-	action.sa_handler = signal_handler;
-	sigemptyset (&action.sa_mask);
-	action.sa_flags = 0;
-	rc = sigaction (SIGINT, &action, NULL);
-	if (rc < 0) {
-		rc = errno;
-		ERROR("Failed on set signal handler: %s\n", strerror(errno));
-		goto err;
-	}
-
-	while((c = getopt(argc, argv, "k")) != -1) {
-		switch(c) {
-		case 'k':
-			check_kernel_log = 1;
-			break;
-		default:
-			usage(argv[0]);
-			goto err;
-		}
-	}
-
-	/* Open the netlink socket for audit events */
-	audit_fd = audit_open();
-	if (audit_fd < 0) {
-		rc = errno;
-		ERROR("Failed on audit_set_pid with error: %s\n", strerror(errno));
-		goto err;
-	}
-
-	l = audit_log_open(LOG_FILE, OLD_LOG_FILE, MAX_LOG_FILE_SIZE);
-	if(!l) {
-		ERROR("Failed on audit_log_open\n");
-		goto err;
-	}
-
-	if (audit_set_pid(audit_fd, getpid(), WAIT_YES) < 0) {
-		rc = errno;
-		ERROR("Failed on audit_set_pid with error: %s\n", strerror(errno));
-		goto err;
-	}
-
-	pfds.fd = audit_fd;
-	pfds.events = POLLIN;
-
-	if(check_kernel_log) {
-		audit_log_put_kmsg(l);
-	}
-
-	while (!quit) {
-
-		/* Start reading for events */
-		rc = poll(&pfds, 1, -1);
-		if (rc == 0) {
-			continue;
-		}
-		else if(rc < 0) {
-			if (errno != EINTR) {
-				ERROR("Failed to poll audit log socket: %d : %s\n", errno, strerror(errno));
-			}
-			continue;
-		}
-
-		if (audit_get_reply(audit_fd, &rep, GET_REPLY_BLOCKING, 0) < 0) {
-			ERROR("Failed on audit_get_reply with error: %s\n", strerror(errno));
-			continue;
-		}
-
-		audit_log_write(l, &rep);
-		/* Keep reading for events */
-	}
+int main(int argc, char *argv[])
+{
+    int c;
+    int rc;
+    int audit_fd = -1;
+    int check_kernel_log = 0;
+
+    struct pollfd pfds;
+    struct audit_reply rep;
+    struct sigaction action;
+    audit_log *l = NULL;
+
+    SLOGI("Starting up");
+
+    drop_privileges_or_die();
+
+    /* register the signal handler */
+    action.sa_handler = signal_handler;
+    sigemptyset(&action.sa_mask);
+    action.sa_flags = 0;
+    rc = sigaction(SIGINT, &action, NULL);
+    if (rc < 0) {
+        rc = errno;
+        SLOGE("Failed on set signal handler: %s", strerror(errno));
+        goto err;
+    }
+
+    while ((c = getopt(argc, argv, "k")) != -1) {
+        switch (c) {
+        case 'k':
+            check_kernel_log = 1;
+            break;
+        default:
+            usage(argv[0]);
+            goto err;
+        }
+    }
+
+    /* Open the netlink socket for audit events */
+    audit_fd = audit_open();
+    if (audit_fd < 0) {
+        rc = errno;
+        SLOGE("Failed on audit_set_pid with error: %s", strerror(errno));
+        goto err;
+    }
+
+    l = audit_log_open(AUDITD_LOG_FILE, AUDITD_OLD_LOG_FILE, AUDITD_MAX_LOG_FILE_SIZE);
+    if (!l) {
+        SLOGE("Failed on audit_log_open");
+        goto err;
+    }
+
+    if (audit_set_pid(audit_fd, getpid(), WAIT_YES) < 0) {
+        rc = errno;
+        SLOGE("Failed on audit_set_pid with error: %s", strerror(errno));
+        goto err;
+    }
+
+    pfds.fd = audit_fd;
+    pfds.events = POLLIN;
+
+    if (check_kernel_log) {
+        audit_log_put_kmsg(l);
+    }
+
+    while (!quit) {
+
+        /* Start reading for events */
+        rc = poll(&pfds, 1, -1);
+        if (rc == 0) {
+            continue;
+        } else if (rc < 0) {
+            if (errno != EINTR) {
+                SLOGE("Failed to poll audit log socket: %d : %s", errno, strerror(errno));
+            }
+            continue;
+        }
+
+        if (audit_get_reply(audit_fd, &rep, GET_REPLY_BLOCKING, 0) < 0) {
+            SLOGE("Failed on audit_get_reply with error: %s", strerror(errno));
+            continue;
+        }
+
+        audit_log_write(l, "type=%d msg=%.*s\n", rep.type, rep.len, rep.msg.data);
+        /* Keep reading for events */
+    }
 
 err:
-	INFO("auditd:  exiting\n");
-	if (audit_fd >= 0) {
-		audit_set_pid(audit_fd, 0, WAIT_NO);
-		audit_close(audit_fd);
-	}
-	audit_log_close(l);
-	return rc;
+    SLOGI("Exiting");
+    if (audit_fd >= 0) {
+        audit_set_pid(audit_fd, 0, WAIT_NO);
+        audit_close(audit_fd);
+    }
+    audit_log_close(l);
+    return rc;
 }

File auditd/auditd.h

-/*
- * Copyright 2012, Samsung Telecommunications of America
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * Written by William Roberts <w.roberts@sta.samsung.com>
- */
-
-#ifndef _AUDITD_H_
-#define _AUDITD_H_
-
-#define LOG_TAG "auditd"
-
-#include <cutils/log.h>
-
-/* Debugging statements that go to the system log
- * aka logcat.
- * The naming convention follows the severity of the
- * message to print.
- */
-#define INFO(...)     SLOGI(__VA_ARGS__)
-#define ERROR(...)    SLOGE(__VA_ARGS__)
-#define WARNING(...)  SLOGW(__VA_ARGS__)
-
-/*
- * Given an errno variable, returns the abs value of it
- * Some of the existing interfaces return a -errno instead of -1
- * with errno set. This is just a way of ensuring that the errno
- * you are using, is a positive value.
- */
-#define GETERRNO(x) ((x < 0) ? -x : x)
-
-#endif
-

File auditd/libaudit.c

  * Written by William Roberts <w.roberts@sta.samsung.com>
  *
  */
+
 #include <errno.h>
+#include <fcntl.h>
 #include <string.h>
+#include <unistd.h>
+#include <stdint.h>
 
+#define LOG_TAG "libaudit"
+#include <cutils/log.h>
 #include <cutils/klog.h>
 
-#include "auditd.h"
 #include "libaudit.h"
 
-/* Only should be used internally */
-extern int audit_send(int fd, int type, const void *data, unsigned int size);
-
-/* Depending on static to initialize this to 0 */
-static const struct audit_status _new_audit_status;
-
-int audit_set_pid(int fd, uint32_t pid, rep_wait_t wmode) {
-
-	int rc;
-	int line;
-	struct audit_reply rep;
-	struct audit_status status = _new_audit_status;
-
-	/*
-	 * In order to set the auditd PID we send an audit message over the netlink socket
-	 * with the pid field of the status struct set to our current pid, and the
-	 * the mask set to AUDIT_STATUS_PID
-	 */
-	status.pid  = pid;
-	status.mask = AUDIT_STATUS_PID;
-
-	/* Let the kernel know this pid will be registering for audit events */
-	rc = audit_send(fd, AUDIT_SET, &status, sizeof(status));
-	if (rc < 0) {
-		line = __LINE__;
-		goto err;
-	}
-
-	/*
-	 * In a request where we need to wait for a response, wait for the message
-	 * and discard it. This message confirms and sync's us with the kernel.
-	 * This daemon is now registered as the audit logger. Only wait if the
-	 * wmode is != WAIT_NO
-	 */
-	if (wmode != WAIT_NO) {
-		/* TODO
-		 * If the daemon dies and restarts the message didn't come back,
-		 * so I went to non-blocking and it seemed to fix the bug.
-		 * Need to investigate further.
-		 */
-		(void)audit_get_reply(fd, &rep, GET_REPLY_NONBLOCKING, 0);
-	}
+/**
+ * Copies the netlink message data to the reply structure.
+ *
+ * When the kernel sends a response back, we must adjust the response from the
+ * netlink message header.
+ * All the data is in rep->msg but belongs in the type enforced fields in the struct.
+ *
+ * @param rep
+ *  The response
+ * @param len
+ *  The length of the message, len must never be less than 0!
+ * @return
+ *  This function returns 0 on success, else -error.
+ */
+static int set_internal_fields(struct audit_reply *rep, ssize_t len)
+{
+    int rc;
+
+    /*
+     * We end up setting a specific field in the union, but since it
+     * is a union and they are all of type pointer, we can just clear
+     * one.
+     */
+    rep->status = NULL;
+
+    /* Set the response from the netlink message */
+    rep->nlh = &rep->msg.nlh;
+    rep->len = rep->msg.nlh.nlmsg_len;
+    rep->type = rep->msg.nlh.nlmsg_type;
+
+    /* Check if the reply from the kernel was ok */
+    if (!NLMSG_OK(rep->nlh, (size_t)len)) {
+        rc = (len == sizeof(rep->msg)) ? -EFBIG : -EBADE;
+        SLOGE("Bad kernel response %s", strerror(-rc));
+        return rc;
+    }
+
+    /* Next we'll set the data structure to point to msg.data. This is
+     * to avoid having to use casts later. */
+    if (rep->type == NLMSG_ERROR) {
+        rep->error = NLMSG_DATA(rep->nlh);
+    } else if (rep->type == AUDIT_GET) {
+        rep->status = NLMSG_DATA(rep->nlh);
+    } else if (rep->type == AUDIT_LIST_RULES) {
+        rep->ruledata = NLMSG_DATA(rep->nlh);
+    } else if (rep->type == AUDIT_SIGNAL_INFO) {
+        rep->signal_info = NLMSG_DATA(rep->nlh);
+    }
+    /* If it is not any of the above specific events, it must be a generic message */
+    else {
+        rep->message = NLMSG_DATA(rep->nlh);
+    }
+
+    return 0;
+}
+
+/**
+ * Waits for an ack from the kernel
+ * @param fd
+ *  The netlink socket fd
+ * @param seq
+ *  The current sequence number were acking on
+ * @return
+ *  This function returns 0 on success, else -errno.
+ */
+static int get_ack(int fd, int16_t seq)
+{
+    int rc;
+    struct audit_reply rep;
+
+    /* Sanity check the input, this is an internal interface this shouldn't happen */
+    if (fd < 0) {
+        return -EINVAL;
+    }
+
+    rc = audit_get_reply(fd, &rep, GET_REPLY_BLOCKING, MSG_PEEK);
+    if (rc < 0) {
+        return rc;
+    }
+
+    if (rep.type == NLMSG_ERROR) {
+        audit_get_reply(fd, &rep, GET_REPLY_BLOCKING, 0);
+        if (rep.error->error) {
+            return -rep.error->error;
+        }
+    }
+
+    if ((int16_t)rep.nlh->nlmsg_seq != seq) {
+        SLOGW("Expected sequence number between user space and kernel space is out of skew, "
+        "expected %u got %u", seq, rep.nlh->nlmsg_seq);
+    }
+
+    return 0;
+}
+
+/**
+ *
+ * @param fd
+ *  The netlink socket fd
+ * @param type
+ *  The type of netlink message
+ * @param data
+ *  The data to send
+ * @param size
+ *  The length of the data in bytes
+ * @return
+ *  This function returns a positive sequence number on success, else -errno.
+ */
+static int audit_send(int fd, int type, const void *data, unsigned int size)
+{
+    int rc;
+    static int16_t sequence = 0;
+    struct audit_message req;
+    struct sockaddr_nl addr;
+
+    memset(&req, 0, sizeof(req));
+    memset(&addr, 0, sizeof(addr));
+
+    /* We always send netlink messaged */
+    addr.nl_family = AF_NETLINK;
+
+    /* Set up the netlink headers */
+    req.nlh.nlmsg_type = type;
+    req.nlh.nlmsg_len = NLMSG_SPACE(size);
+    req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+
+    /*
+     * Check for a valid fd, even though sendto would catch this, its easier to always
+     * blindly increment the sequence number
+     */
+    if (fd < 0) {
+        return -EBADF;
+    }
+
+    /* Ensure the message is not too big */
+    if (NLMSG_SPACE(size) > MAX_AUDIT_MESSAGE_LENGTH) {
+        SLOGE("netlink message is too large");
+        return -EINVAL;
+    }
+
+    /* Only memcpy in the data if it was specified */
+    if (size && data)
+        memcpy(NLMSG_DATA(&req.nlh), data, size);
+
+    /*
+     * Only increment the sequence number on a guarantee
+     * you will send it to the kernel.
+     *
+     * Also, the sequence is defined as a u32 in the kernel
+     * struct. Using an int here might not work on 32/64 bit splits. A
+     * signed 64 bit value can overflow a u32..but a u32
+     * might not fit in the response, so we need to use s32.
+     * Which is still kind of hackish since int could be 16 bits
+     * in size. The only safe type to use here is a signed 16
+     * bit value.
+     */
+    req.nlh.nlmsg_seq = ++sequence;
+
+    /* While failing and its due to interrupts */
+    do {
+        /* Try and send the netlink message */
+        rc = sendto(fd, &req, req.nlh.nlmsg_len, 0, (struct sockaddr*) &addr, sizeof(addr));
+
+    } while (rc < 0 && errno == EINTR);
+
+    /* Not all the bytes were sent */
+    if ((uint32_t) rc != req.nlh.nlmsg_len) {
+        rc = -EPROTO;
+        goto out;
+    } else if (rc < 0) {
+        rc = -errno;
+        SLOGE("Error sending data over the netlink socket: %s", strerror(-errno));
+        goto out;
+    }
+
+    /* We sent all the bytes, get the ack */
+    rc = get_ack(fd, sequence);
+
+    /* If the ack failed, return the error, else return the sequence number */
+    rc = (rc == 0) ? (int) sequence : rc;
 
 out:
-	return rc;
+    /* Don't let sequence roll to negative */
+    if (sequence < 0) {
+        SLOGW("Auditd to Kernel sequence number has rolled over");
+        sequence = 0;
+    }
+
+    return rc;
+}
+
+int audit_set_pid(int fd, uint32_t pid, rep_wait_t wmode)
+{
+    int rc;
+    struct audit_reply rep;
+    struct audit_status status;
+
+    memset(&status, 0, sizeof(status));
+
+    /*
+     * In order to set the auditd PID we send an audit message over the netlink socket
+     * with the pid field of the status struct set to our current pid, and the
+     * the mask set to AUDIT_STATUS_PID
+     */
+    status.pid = pid;
+    status.mask = AUDIT_STATUS_PID;
+
+    /* Let the kernel know this pid will be registering for audit events */
+    rc = audit_send(fd, AUDIT_SET, &status, sizeof(status));
+    if (rc < 0) {
+        SLOGE("Could net set pid for audit events, error: %s", strerror(-rc));
+        return rc;
+    }
+
+    /*
+     * In a request where we need to wait for a response, wait for the message
+     * and discard it. This message confirms and sync's us with the kernel.
+     * This daemon is now registered as the audit logger. Only wait if the
+     * wmode is != WAIT_NO
+     */
+    if (wmode != WAIT_NO) {
+        /* TODO
+         * If the daemon dies and restarts the message didn't come back,
+         * so I went to non-blocking and it seemed to fix the bug.
+         * Need to investigate further.
+         */
+        audit_get_reply(fd, &rep, GET_REPLY_NONBLOCKING, 0);
+    }
+
+    return 0;
+}
+
+int audit_open()
+{
+    return socket(PF_NETLINK, SOCK_RAW, NETLINK_AUDIT);
+}
+
+int audit_get_reply(int fd, struct audit_reply *rep, reply_t block, int peek)
+{
+    ssize_t len;
+    int flags;
+
+    struct sockaddr_nl nladdr;
+    socklen_t nladdrlen = sizeof(nladdr);
+
+    if (fd < 0) {
+        return -EBADF;
+    }
+
+    /* Set up the flags for recv from */
+    flags = (block == GET_REPLY_NONBLOCKING) ? MSG_DONTWAIT : 0;
+    flags |= peek;
+
+    /*
+     * Get the data from the netlink socket but on error we need to be carefull,
+     * the interface shows that EINTR can never be returned, other errors, however,
+     * can be returned.
+     */
+    do {
+        len = recvfrom(fd, &rep->msg, sizeof(rep->msg), flags, (struct sockaddr*) &nladdr,
+                &nladdrlen);
+
+        /*
+         * EAGAIN and EINTR should be re-tried until success or
+         * another error manifests.
+         */
+        if (len < 0 && errno != EINTR) {
+            if (block == GET_REPLY_NONBLOCKING && errno == EAGAIN) {
+                /* If the request is non blocking and the errno is EAGAIN, just return 0 */
+                return 0;
+            }
+            SLOGE("Error receiving from netlink socket, error: %s", strerror(errno));
+            return -errno;
+        }
+
+        /* 0 or greater indicates success */
+    } while (len < 0);
+
+    if (nladdrlen != sizeof(nladdr)) {
+        SLOGE("Protocol fault, error: %s", strerror(EPROTO));
+        return -EPROTO;
+    }
+
+    /* Make sure the netlink message was not spoof'd */
+    if (nladdr.nl_pid) {
+        SLOGE("Invalid netlink pid received, expected 0 got: %d", nladdr.nl_pid);
+        return -EINVAL;
+    }
+
+    return set_internal_fields(rep, len);
+}
 
-err:
-	errno = GETERRNO(rc);
-	ERROR("%s    Failed in %s around line %d with error: %s\n", __FILE__, __FUNCTION__, line, strerror(errno));
-	rc = -1;
-	goto out;
+void audit_close(int fd)
+{
+    int rc = close(fd);
+    if (rc < 0) {
+        SLOGE("Attempting to close invalid fd %d, error: %s", fd, strerror(errno));
+    }
+    return;
 }

File auditd/libaudit.h

+/*
+ * Copyright 2012, Samsung Telecommunications of America
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Written by William Roberts <w.roberts@sta.samsung.com>
+ */
+
 #ifndef _LIBAUDIT_H_
 #define _LIBAUDIT_H_
+
 #include <stdint.h>
 #include <sys/socket.h>
 #include <sys/types.h>
 
 #define MAX_AUDIT_MESSAGE_LENGTH    8970
 
-typedef enum { GET_REPLY_BLOCKING=0, GET_REPLY_NONBLOCKING } reply_t;
-typedef enum { WAIT_NO, WAIT_YES } rep_wait_t;
+typedef enum {
+    GET_REPLY_BLOCKING=0,
+    GET_REPLY_NONBLOCKING
+} reply_t;
+
+typedef enum {
+    WAIT_NO,
+    WAIT_YES
+} rep_wait_t;
 
 struct audit_sig_info {
-	uid_t uid;
-	pid_t pid;
-	char ctx[0];
+    uid_t uid;
+    pid_t pid;
+    char ctx[0];
 };
 
 struct audit_message {
     };
 };
 
+/**
+ * Opens a connection to the Audit netlink socket
+ * @return
+ *  A valid fd on success or < 0 on error with errno set.
+ *  Returns the same errors as man 2 socket.
+ */
 extern int  audit_open(void);
+
+/**
+ * Closes the fd returned from audit_open()
+ * @param fd
+ *  The fd to close
+ */
 extern void audit_close(int fd);
+
+/**
+ *
+ * @param fd
+ *  The fd returned by a call to audit_open()
+ * @param rep
+ *  The response struct to store the response in.
+ * @param block
+ *  Whether or not to block on IO
+ * @param peek
+ *  Whether or not we are to remove the message from
+ *  the queue when we do a read on the netlink socket.
+ * @return
+ *  This function returns 0 on success, else -errno.
+ */
 extern int  audit_get_reply(int fd, struct audit_reply *rep, reply_t block,
                int peek);
+
+/**
+ * Sets a pid to recieve audit netlink events from the kernel
+ * @param fd
+ *  The fd returned by a call to audit_open()
+ * @param pid
+ *  The pid whom to set as the reciever of audit messages
+ * @param wmode
+ *  Whether or not to block on the underlying socket io calls.
+ * @return
+ *  This function returns 0 on success, -errno on error.
+ */
 extern int  audit_set_pid(int fd, uint32_t pid, rep_wait_t wmode);
 
 #endif

File auditd/netlink.c

-/*
- * Copyright 2012, Samsung Telecommunications of America
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * Written by William Roberts <w.roberts@sta.samsung.com>
- *
- */
-#include <errno.h>
-#include <fcntl.h>
-#include <string.h>
-#include <unistd.h>
-#include <stdint.h>
-
-#include <cutils/klog.h>
-
-#include "auditd.h"
-#include "libaudit.h"
-
-/* Relying on static to initialize to 0, these are used to initialize structs to 0 */
-static const struct audit_message _new_req;
-static const struct sockaddr_nl _new_addr;
-
-/**
- * Copies the netlink message data to the reply structure.
- *
- * When the kernel sends a response back, we must adjust the response from the nlmsghdr.
- * All the data is is rep->msg but belongs in type enforced fields in the struct.
- *
- * @param rep
- *  The response
- * @param len
- *  The length of ther message, len must never be less than 0!
- * @return
- *  This function returns 0 on success.
- */
-static int set_internal_fields(struct audit_reply *rep, ssize_t len) {
-
-	int rc = 0;
-	int line = 0;
-
-	/*
-	 * We end up setting a specific field in the union, but since it
-	 * is a union and they are all of type pointer, we can just clear
-	 * one.
-	 */
-	rep->status = NULL;
-
-	/* Set the response from the netlink message */
-	rep->nlh      = &rep->msg.nlh;
-	rep->len      = rep->msg.nlh.nlmsg_len;
-	rep->type     = rep->msg.nlh.nlmsg_type;
-
-	/* Check if the reply from the kernel was ok */
-	if (!NLMSG_OK(rep->nlh, (size_t)len)) {
-		rc = (len == sizeof(rep->msg)) ? EFBIG : EBADE;
-		line = __LINE__;
-		goto err;
-	}
-
-	/* Next we'll set the data structure to point to msg.data. This is
-	 * to avoid having to use casts later. */
-	if (rep->type == NLMSG_ERROR) {
-		rep->error = NLMSG_DATA(rep->nlh);
-	}
-	else if (rep->type == AUDIT_GET) {
-		rep->status  = NLMSG_DATA(rep->nlh);
-	}
-	else if (rep -> type == AUDIT_LIST_RULES) {
-		rep->ruledata = NLMSG_DATA(rep->nlh);
-	}
-	else if (rep->type == AUDIT_SIGNAL_INFO) {
-		rep->signal_info = NLMSG_DATA(rep->nlh);
-	}
-	/* If it is not any of the above specific events, it must be a generic message */
-	else {
-		rep->message = NLMSG_DATA(rep->nlh);
-	}
-out:
-	return rc;
-err:
-	errno = GETERRNO(rc);
-	ERROR("%s    Failed in %s around line %d with error: %s\n", __FILE__, __FUNCTION__, line, strerror(errno));
-	rc = -1;
-	goto out;
-}
-
-/**
- * Waits for an ack from the kernel
- * @param fd
- *  The netlink socket fd
- * @param seq
- *  The current sequence number were acking on
- * @return
- *  0 on success
- */
-static int get_ack(int fd, int16_t seq) {
-
-	int rc = 0;
-	int line = 0;
-
-	struct audit_reply rep;
-
-	/* Sanity check the input, this is an internal interface this shouldn't happen */
-	if (fd < 0) {
-		rc = EINVAL;
-		line = __LINE__;
-		goto err;
-	}
-
-	rc = -audit_get_reply(fd, &rep, GET_REPLY_BLOCKING, MSG_PEEK);
-	if(rc < 0) {
-		line = __LINE__;
-		goto err;
-	}
-	else if (rep.type == NLMSG_ERROR) {
-		(void)audit_get_reply(fd, &rep, GET_REPLY_BLOCKING, 0);
-		if (rep.error->error) {
-			line = __LINE__;
-			rc = rep.error->error;
-			goto err;
-		}
-	}
-out:
-	return rc;
-err:
-	errno = GETERRNO(rc);
-	ERROR("%s    Failed in %s around line %d with error: %s\n", __FILE__, __FUNCTION__, line, strerror(errno));
-	rc = -1;
-	goto out;
-}
-
-/**
- * Opens a connection to the Audit netlink socket
- * @return
- *  A valid fd on success or < 0 on error with errno set.
- *  Returns the same errors as man 2 socket.
- */
-int audit_open() {
-	return socket(PF_NETLINK, SOCK_RAW, NETLINK_AUDIT);
-}
-
-/**
- *
- * @param fd
- *  The fd returned by a call to audit_open()
- * @param rep
- *  The response struct to store the response in.
- * @param block
- *  Whether or not to block on IO
- * @param peek
- *  Whether or not we are to remove the message from
- *  the queue when we do a read on the netlink socket.
- * @return
- *  0 on success, errno on error
- */
-int audit_get_reply(int fd, struct audit_reply *rep, reply_t block, int peek) {
-
-	int rc;
-	ssize_t len;
-	int flags;
-	int line = 0;
-
-	struct sockaddr_nl nladdr;
-	socklen_t nladdrlen = sizeof(nladdr);
-
-	if (fd < 0) {
-		rc = EBADF;
-		line = __LINE__;
-		goto err;
-	}
-
-	/* Set up the flags for recv from */
-	flags = (block == GET_REPLY_NONBLOCKING) ? MSG_DONTWAIT : 0;
-	flags |= peek;
-
-	/*
-	 * Get the data from the netlink socket but on error we need to be carefull,
-	 * the interface shows that EINTR can never be returned, other errors, however,
-	 * can be returned.
-	 */
-	do {
-
-		len = recvfrom(fd, &rep->msg, sizeof(rep->msg), flags,
-			(struct sockaddr*)&nladdr, &nladdrlen);
-
-		/*
-		 * EAGAIN and EINTR should be re-tried until success or
-		 * another error manifests.
-		 */
-		if (len < 0 && errno != EINTR) {
-			if (block == GET_REPLY_NONBLOCKING && errno == EAGAIN) {
-				rc = 0;
-				goto out;
-			}
-			rc = errno;
-			line = __LINE__;
-			goto err;
-		}
-
-	/* 0 or greater indicates success */
-	} while (len < 0);
-
-	if (nladdrlen != sizeof(nladdr)) {
-		rc = EPROTO;
-		line == __LINE__;
-		goto err;
-	}
-
-	/* Make sure the netlink message was not spoof'd */
-	if (nladdr.nl_pid) {
-		rc = EINVAL;
-		line == __LINE__;
-		goto err;
-	}
-
-	rc = set_internal_fields(rep, len);
-	if (rc < 0) {
-		rc = errno;
-		line == __LINE__;
-		goto err;
-	}
-
-out:
-	return rc;
-err:
-	errno = GETERRNO(rc);
-	ERROR("%s    Failed in %s around line %d with error: %s\n", __FILE__, __FUNCTION__, line, strerror(errno));
-	rc = -1;
-	goto out;
-}
-
-/**
- * Closes the fd returned from audit_open()
- * @param fd
- *  The fd to close
- *
- * @note
- *  This function was left void to be complaint
- *  to an existing interface, however it clears
- *  errno on entry, so errno can be used to check
- *  if the fd you gave close was wrong.
- *
- */
-void audit_close(int fd) {
-
-	int line = 0;
-	int rc = close(fd);
-	if(rc) {
-		line == __LINE__;
-		rc = errno;
-		goto err;
-	}
-out:
-	return;
-
-err:
-	errno = GETERRNO(rc);
-	ERROR("%s    Failed in %s around line %d with error: %s\n", __FILE__, __FUNCTION__, line, strerror(errno));
-	goto out;
-}
-
-/**
- *
- * @param fd
- *  The netlink socket fd
- * @param type
- *  The type of netlink message
- * @param data
- *  The data to send
- * @param size
- *  The length of the data in bytes
- * @return
- *  Sequence number on success or -errno on error.
- */
-int audit_send(int fd, int type, const void *data, unsigned int size) {
-
-	int rc = 0;
-	static int16_t sequence = 0;
-	struct audit_message req = _new_req;
-	struct sockaddr_nl addr = _new_addr;
-
-	/* We always send netlink messaged */
-	addr.nl_family = AF_NETLINK;
-
-	/* Set up the netlink headers */
-	req.nlh.nlmsg_type = type;
-	req.nlh.nlmsg_len = NLMSG_SPACE(size);
-	req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
-
-	/*
-	 * Check for a valid fd, even though sendto would catch this, its easier to always
-	 * blindly increment the sequence number
-	 */
-	if (fd < 0) {
-		rc = EBADF;
-		goto err;
-	}
-
-	/* Ensure the message is not too big */
-	if (NLMSG_SPACE(size) > MAX_AUDIT_MESSAGE_LENGTH) {
-		rc = EINVAL;
-		goto err;
-	}
-
-	/* Only memcpy in the data if it was specified */
-	if (size && data)
-		memcpy(NLMSG_DATA(&req.nlh), data, size);
-
-	/*
-	 * Only increment the sequence number on a guarantee
-	 * you will send it to the kernel.
-	 *
-	 * Also, the sequence is defined as a u32 in the kernel
-	 * struct. Using an int here might not work on 32/64 bit splits. A
-	 * signed 64 bit value can overflow a u32..but a u32
-	 * might not fit in the response, so we need to use s32.
-	 * Which is still kind of hackish since int could be 16 bits
-	 * in size. The only safe type to use here is a signed 16
-	 * bit value.
-	 */
-	req.nlh.nlmsg_seq = ++sequence;
-
-	/* While failing and its due to interrupts */
-	do {
-		/* Try and send the netlink message */
-		rc = sendto(fd, &req, req.nlh.nlmsg_len, 0,
-			(struct sockaddr*)&addr, sizeof(addr));
-
-	} while (rc < 0 && errno == EINTR);
-
-	/* Not all the bytes were sent */
-	if ((uint32_t)rc != req.nlh.nlmsg_len) {
-		rc = EPROTO;
-		goto err;
-	}
-	else if (rc < 0) {
-		rc = errno;
-		goto out;
-	}
-
-	/* We sent all the bytes, get the ack */
-	rc = (get_ack(fd, sequence) == 0) ? (int)sequence : rc;
-
-out:
-
-	/* Don't let sequence roll to negative */
-	sequence = (sequence < 0) ? 0 : sequence;
-
-	return rc;
-
-err:
-	errno = rc;
-	rc = -rc;
-	goto out;
-}
-