aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/audit/lib/audit_logging.c
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/audit/lib/audit_logging.c')
-rw-r--r--framework/src/audit/lib/audit_logging.c746
1 files changed, 746 insertions, 0 deletions
diff --git a/framework/src/audit/lib/audit_logging.c b/framework/src/audit/lib/audit_logging.c
new file mode 100644
index 00000000..c9461061
--- /dev/null
+++ b/framework/src/audit/lib/audit_logging.c
@@ -0,0 +1,746 @@
+/* audit_logging.c --
+ * Copyright 2005-2008,2010,2011,2013 Red Hat Inc., Durham, North Carolina.
+ * All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Authors:
+ * Steve Grubb <sgrubb@redhat.com>
+ */
+
+#include "config.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <netinet/in.h> // inet6 addrlen
+#include <netdb.h> // gethostbyname
+#include <arpa/inet.h> // inet_ntop
+#include <utmp.h>
+#include <limits.h> // PATH_MAX
+
+#include "libaudit.h"
+#include "private.h"
+
+#define TTY_PATH 32
+#define MAX_USER (UT_NAMESIZE * 2) + 8
+
+// NOTE: The kernel fills in pid, uid, and loginuid of sender. Therefore,
+// these routines do not need to send them.
+
+/*
+ * resolve's the hostname - caller must pass a INET6_ADDRSTRLEN byte buffer
+ * Returns string w/ numerical address, or "?" on failure
+ */
+static void _resolve_addr(char buf[], const char *host)
+{
+ struct addrinfo *ai;
+ struct addrinfo hints;
+ int e;
+
+ buf[0] = '?';
+ buf[1] = 0;
+ /* Short circuit this lookup if NULL, or empty */
+ if (host == NULL || *host == 0)
+ return;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_ADDRCONFIG;
+ hints.ai_socktype = SOCK_STREAM;
+
+ e = getaddrinfo(host, NULL, &hints, &ai);
+ if (e != 0) {
+ audit_msg(LOG_ERR,
+ "resolve_addr: cannot resolve hostname %s (%s)",
+ host, gai_strerror(e));
+ return;
+ }
+ // What to do if more than 1 addr?
+ inet_ntop(ai->ai_family, ai->ai_family == AF_INET ?
+ (void *) &((struct sockaddr_in *)ai->ai_addr)->sin_addr :
+ (void *) &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr,
+ buf, INET6_ADDRSTRLEN);
+ freeaddrinfo(ai);
+}
+
+/*
+ * This function checks a string to see if it needs encoding. It
+ * return 1 if needed and 0 if not
+ */
+int audit_value_needs_encoding(const char *str, unsigned int size)
+{
+ unsigned int i;
+
+ if (str == NULL)
+ return 0;
+
+ for (i=0; i<size; i++) {
+ // we don't test for > 0x7f because str[] is signed.
+ if (str[i] == '"' || str[i] < 0x21 || str[i] == 0x7F)
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * This function does encoding of "untrusted" names just like the kernel
+ */
+char *audit_encode_value(char *final, const char *buf, unsigned int size)
+{
+ unsigned int i;
+ char *ptr = final;
+ const char *hex = "0123456789ABCDEF";
+
+ if (final == NULL)
+ return NULL;
+
+ if (buf == NULL) {
+ *final = 0;
+ return final;
+ }
+
+ for (i=0; i<size; i++) {
+ *ptr++ = hex[(buf[i] & 0xF0)>>4]; /* Upper nibble */
+ *ptr++ = hex[buf[i] & 0x0F]; /* Lower nibble */
+ }
+ *ptr = 0;
+ return final;
+}
+
+char *audit_encode_nv_string(const char *name, const char *value,
+ unsigned int vlen)
+{
+ char *str;
+
+ if (vlen == 0 && value)
+ vlen = strlen(value);
+
+ if (value && audit_value_needs_encoding(value, vlen)) {
+ char *tmp = malloc(2*vlen + 1);
+ if (tmp) {
+ audit_encode_value(tmp, value, vlen);
+ if (asprintf(&str, "%s=%s", name, tmp) < 0)
+ str = NULL;
+ free(tmp);
+ } else
+ str = NULL;
+ } else
+ if (asprintf(&str, "%s=\"%s\"", name, value ? value : "?") < 0)
+ str = NULL;
+ return str;
+}
+
+/*
+ * Get the executable's name
+ */
+static char *_get_exename(char *exename, int size)
+{
+ int res;
+ char tmp[PATH_MAX+1];
+
+ /* get the name of the current executable */
+ if ((res = readlink("/proc/self/exe", tmp, PATH_MAX)) == -1) {
+ strcpy(exename, "\"?\"");
+ audit_msg(LOG_ERR, "get_exename: cannot determine executable");
+ } else {
+ tmp[res] = '\0';
+ if (audit_value_needs_encoding(tmp, res))
+ return audit_encode_value(exename, tmp, res);
+ snprintf(exename, size, "\"%s\"", tmp);
+ }
+ return exename;
+}
+
+/*
+ * Get the command line name
+ * NOTE: at the moment, this only escapes what the user sent
+ */
+static char *_get_commname(const char *comm, char *commname, unsigned int size)
+{
+ unsigned int len;
+
+ if (comm == NULL) {
+ strcpy(commname, "\"?\"");
+ return commname;
+ }
+
+ len = strlen(comm);
+ if (audit_value_needs_encoding(comm, len))
+ audit_encode_value(commname, comm, len);
+ else
+ snprintf(commname, size, "\"%s\"", comm);
+
+ return commname;
+}
+
+static int check_ttyname(const char *ttyn)
+{
+ struct stat statbuf;
+
+ if (lstat(ttyn, &statbuf)
+ || !S_ISCHR(statbuf.st_mode)
+ || (statbuf.st_nlink > 1 && strncmp(ttyn, "/dev/", 5))) {
+ audit_msg(LOG_ERR, "FATAL: bad tty %s", ttyn);
+ return 1;
+ }
+ return 0;
+}
+
+static const char *_get_tty(char *tname, int size)
+{
+ int rc, i, found = 0;
+
+ for (i=0; i<3 && !found; i++) {
+ rc = ttyname_r(i, tname, size);
+ if (rc == 0 && tname[0] != '\0')
+ found = 1;
+ }
+
+ if (!found)
+ return NULL;
+
+ if (check_ttyname(tname))
+ return NULL;
+
+ if (strncmp(tname, "/dev/", 5) == 0)
+ return &tname[5];
+
+ return tname;
+}
+
+/*
+ * This function will log a message to the audit system using a predefined
+ * message format. This function should be used by all console apps that do
+ * not manipulate accounts or groups.
+ *
+ * audit_fd - The fd returned by audit_open
+ * type - type of message, ex: AUDIT_USER, AUDIT_USYS_CONFIG, AUDIT_USER_LOGIN
+ * message - the message being sent
+ * hostname - the hostname if known
+ * addr - The network address of the user
+ * tty - The tty of the user
+ * result - 1 is "success" and 0 is "failed"
+ *
+ * It returns the sequence number which is > 0 on success or <= 0 on error.
+ */
+int audit_log_user_message(int audit_fd, int type, const char *message,
+ const char *hostname, const char *addr, const char *tty, int result)
+{
+ char buf[MAX_AUDIT_MESSAGE_LENGTH];
+ char addrbuf[INET6_ADDRSTRLEN];
+ static char exename[PATH_MAX*2]="";
+ char ttyname[TTY_PATH];
+ const char *success;
+ int ret;
+
+ if (audit_fd < 0)
+ return 0;
+
+ if (result)
+ success = "success";
+ else
+ success = "failed";
+
+ /* If hostname is empty string, make it NULL ptr */
+ if (hostname && *hostname == 0)
+ hostname = NULL;
+ addrbuf[0] = 0;
+ if (addr == NULL || strlen(addr) == 0)
+ _resolve_addr(addrbuf, hostname);
+ else
+ strncat(addrbuf, addr, sizeof(addrbuf)-1);
+
+ if (exename[0] == 0)
+ _get_exename(exename, sizeof(exename));
+ if (tty == NULL)
+ tty = _get_tty(ttyname, TTY_PATH);
+ else if (*tty == 0)
+ tty = NULL;
+
+ snprintf(buf, sizeof(buf),
+ "%s exe=%s hostname=%s addr=%s terminal=%s res=%s",
+ message, exename,
+ hostname ? hostname : "?",
+ addrbuf,
+ tty ? tty : "?",
+ success
+ );
+
+ errno = 0;
+ ret = audit_send_user_message( audit_fd, type, HIDE_IT, buf );
+ if ((ret < 1) && errno == 0)
+ errno = ret;
+ return ret;
+}
+
+/*
+ * This function will log a message to the audit system using a predefined
+ * message format. This function should be used by all console apps that do
+ * not manipulate accounts or groups and are executing a script. An example
+ * would be python or crond wanting to say what they are executing.
+ *
+ * audit_fd - The fd returned by audit_open
+ * type - type of message, ex: AUDIT_USER, AUDIT_USYS_CONFIG, AUDIT_USER_LOGIN
+ * message - the message being sent
+ * comm - the program command line name
+ * hostname - the hostname if known
+ * addr - The network address of the user
+ * tty - The tty of the user
+ * result - 1 is "success" and 0 is "failed"
+ *
+ * It returns the sequence number which is > 0 on success or <= 0 on error.
+ */
+int audit_log_user_comm_message(int audit_fd, int type, const char *message,
+ const char *comm, const char *hostname, const char *addr,
+ const char *tty, int result)
+{
+ char buf[MAX_AUDIT_MESSAGE_LENGTH];
+ char addrbuf[INET6_ADDRSTRLEN];
+ static char exename[PATH_MAX*2]="";
+ char commname[PATH_MAX*2];
+ char ttyname[TTY_PATH];
+ const char *success;
+ int ret;
+
+ if (audit_fd < 0)
+ return 0;
+
+ if (result)
+ success = "success";
+ else
+ success = "failed";
+
+ /* If hostname is empty string, make it NULL ptr */
+ if (hostname && *hostname == 0)
+ hostname = NULL;
+ addrbuf[0] = 0;
+ if (addr == NULL || strlen(addr) == 0)
+ _resolve_addr(addrbuf, hostname);
+ else
+ strncat(addrbuf, addr, sizeof(addrbuf)-1);
+ if (exename[0] == 0)
+ _get_exename(exename, sizeof(exename));
+ if (tty == NULL)
+ tty = _get_tty(ttyname, TTY_PATH);
+ else if (*tty == 0)
+ tty = NULL;
+
+ _get_commname(comm, commname, sizeof(commname));
+
+ snprintf(buf, sizeof(buf),
+ "%s comm=%s exe=%s hostname=%s addr=%s terminal=%s res=%s",
+ message, commname, exename,
+ hostname ? hostname : "?",
+ addrbuf,
+ tty ? tty : "?",
+ success
+ );
+
+ errno = 0;
+ ret = audit_send_user_message( audit_fd, type, HIDE_IT, buf );
+ if ((ret < 1) && errno == 0)
+ errno = ret;
+ return ret;
+}
+
+
+/*
+ * This function will log a message to the audit system using a predefined
+ * message format. It should be used for all account manipulation operations.
+ * Parameter usage is as follows:
+ *
+ * audit_fd - The fd returned by audit_open
+ * type - type of message: AUDIT_USER_CHAUTHTOK for changing any account
+ * attributes.
+ * pgname - program's name
+ * op - operation. "adding user", "changing finger info", "deleting group"
+ * name - user's account or group name. If not available use NULL.
+ * id - uid or gid that the operation is being performed on. This is used
+ * only when user is NULL.
+ * host - The hostname if known
+ * addr - The network address of the user
+ * tty - The tty of the user
+ * result - 1 is "success" and 0 is "failed"
+ *
+ * It returns the sequence number which is > 0 on success or <= 0 on error.
+ */
+int audit_log_acct_message(int audit_fd, int type, const char *pgname,
+ const char *op, const char *name, unsigned int id,
+ const char *host, const char *addr, const char *tty, int result)
+{
+ const char *success;
+ char buf[MAX_AUDIT_MESSAGE_LENGTH];
+ char addrbuf[INET6_ADDRSTRLEN];
+ static char exename[PATH_MAX*2] = "";
+ char ttyname[TTY_PATH];
+ int ret;
+
+ if (audit_fd < 0)
+ return 0;
+
+ if (result)
+ success = "success";
+ else
+ success = "failed";
+
+ /* If hostname is empty string, make it NULL ptr */
+ if (host && *host == 0)
+ host = NULL;
+ addrbuf[0] = 0;
+ if (addr == NULL || strlen(addr) == 0)
+ _resolve_addr(addrbuf, host);
+ else
+ strncat(addrbuf, addr, sizeof(addrbuf)-1);
+
+ if (pgname == NULL) {
+ if (exename[0] == 0)
+ _get_exename(exename, sizeof(exename));
+ } else if (pgname[0] != '"')
+ snprintf(exename, sizeof(exename), "\"%s\"", pgname);
+ else
+ snprintf(exename, sizeof(exename), "%s", pgname);
+
+ if (tty == NULL)
+ tty = _get_tty(ttyname, TTY_PATH);
+ else if (*tty == 0)
+ tty = NULL;
+
+ if (name && id == -1) {
+ char user[MAX_USER];
+ const char *format;
+ size_t len;
+
+ user[0] = 0;
+ strncat(user, name, MAX_USER-1);
+ len = strnlen(user, UT_NAMESIZE);
+ user[len] = 0;
+ if (audit_value_needs_encoding(name, len)) {
+ audit_encode_value(user, name, len);
+ format =
+ "op=%s acct=%s exe=%s hostname=%s addr=%s terminal=%s res=%s";
+ } else
+ format =
+ "op=%s acct=\"%s\" exe=%s hostname=%s addr=%s terminal=%s res=%s";
+
+ snprintf(buf, sizeof(buf), format,
+ op, user, exename,
+ host ? host : "?",
+ addrbuf,
+ tty ? tty : "?",
+ success
+ );
+ } else
+ snprintf(buf, sizeof(buf),
+ "op=%s id=%u exe=%s hostname=%s addr=%s terminal=%s res=%s",
+ op, id, exename,
+ host ? host : "?",
+ addrbuf,
+ tty ? tty : "?",
+ success
+ );
+
+ errno = 0;
+ ret = audit_send_user_message(audit_fd, type, REAL_ERR, buf);
+ if ((ret < 1) && errno == 0)
+ errno = ret;
+ return ret;
+}
+
+/*
+ * This function will log a message to the audit system using a predefined
+ * message format. This function should be used by all apps that are SE Linux
+ * object managers.
+ *
+ * audit_fd - The fd returned by audit_open
+ * type - type of message, ex: AUDIT_USER, AUDIT_USYS_CONFIG, AUDIT_USER_LOGIN
+ * message - the message being sent
+ * hostname - the hostname if known
+ * addr - The network address of the user
+ * tty - The tty of the user
+ * uid - The auid of the person related to the avc message
+ *
+ * It returns the sequence number which is > 0 on success or <= 0 on error.
+ */
+int audit_log_user_avc_message(int audit_fd, int type, const char *message,
+ const char *hostname, const char *addr, const char *tty, uid_t uid)
+{
+ char buf[MAX_AUDIT_MESSAGE_LENGTH];
+ char addrbuf[INET6_ADDRSTRLEN];
+ static char exename[PATH_MAX*2] = "";
+ char ttyname[TTY_PATH];
+ int retval;
+
+ if (audit_fd < 0)
+ return 0;
+
+ /* If hostname is empty string, make it NULL ptr */
+ if (hostname && *hostname == 0)
+ hostname = NULL;
+ addrbuf[0] = 0;
+ if (addr == NULL || strlen(addr) == 0)
+ _resolve_addr(addrbuf, hostname);
+ else
+ strncat(addrbuf, addr, sizeof(addrbuf)-1);
+ if (exename[0] == 0)
+ _get_exename(exename, sizeof(exename));
+ if (tty == NULL)
+ tty = _get_tty(ttyname, TTY_PATH);
+ else if (*tty == 0)
+ tty = NULL;
+
+ snprintf(buf, sizeof(buf),
+ "%s exe=%s sauid=%d hostname=%s addr=%s terminal=%s",
+ message, exename, uid,
+ hostname ? hostname : "?",
+ addrbuf,
+ tty ? tty : "?"
+ );
+
+ errno = 0;
+ retval = audit_send_user_message( audit_fd, type, REAL_ERR, buf );
+ if (retval == -EPERM && getuid() != 0) {
+ syslog(LOG_ERR, "Can't send to audit system: %s %s",
+ audit_msg_type_to_name(type), buf);
+ return 0;
+ }
+ if ((retval < 1) && errno == 0)
+ errno = retval;
+ return retval;
+}
+
+/*
+ * This function will log a message to the audit system using a predefined
+ * message format. It should be used for all SE linux user and role
+ * manipulation operations.
+ * Parameter usage is as follows:
+ *
+ * type - type of message: AUDIT_ROLE_ASSIGN/REMOVE for changing any SE Linux
+ * user or role attributes.
+ * pgname - program's name
+ * op - operation. "adding-user", "adding-role", "deleting-user", "deleting-role"
+ * name - user's account. If not available use NULL.
+ * id - uid that the operation is being performed on. This is used
+ * only when name is NULL.
+ * new_seuser - the new seuser that the login user is getting
+ * new_role - the new_role that the login user is getting
+ * new_range - the new mls range that the login user is getting
+ * old_seuser - the old seuser that the login usr had
+ * old_role - the old role that the login user had
+ * old_range - the old mls range that the login usr had
+ * host - The hostname if known
+ * addr - The network address of the user
+ * tty - The tty of the user
+ * result - 1 is "success" and 0 is "failed"
+ *
+ * It returns the sequence number which is > 0 on success or <= 0 on error.
+ */
+int audit_log_semanage_message(int audit_fd, int type, const char *pgname,
+ const char *op, const char *name, unsigned int id,
+ const char *new_seuser, const char *new_role, const char *new_range,
+ const char *old_seuser, const char *old_role, const char *old_range,
+ const char *host, const char *addr,
+ const char *tty, int result)
+{
+ const char *success;
+ char buf[MAX_AUDIT_MESSAGE_LENGTH];
+ char addrbuf[INET6_ADDRSTRLEN];
+ static char exename[PATH_MAX*2] = "";
+ char ttyname[TTY_PATH];
+ int ret;
+
+ if (audit_fd < 0)
+ return 0;
+
+ if (result)
+ success = "success";
+ else
+ success = "failed";
+
+ /* If hostname is empty string, make it NULL ptr */
+ if (host && *host == 0)
+ host = NULL;
+ addrbuf[0] = 0;
+ if (addr == NULL || strlen(addr) == 0)
+ _resolve_addr(addrbuf, host);
+ else
+ strncat(addrbuf, addr, sizeof(addrbuf)-1);
+
+ if (pgname == NULL || strlen(pgname) == 0) {
+ if (exename[0] == 0)
+ _get_exename(exename, sizeof(exename));
+ pgname = exename;
+ }
+ if (tty == NULL || strlen(tty) == 0)
+ tty = _get_tty(ttyname, TTY_PATH);
+ else if (*tty == 0)
+ tty = NULL;
+
+ if (name && strlen(name) > 0) {
+ size_t len;
+ const char *format;
+ char user[MAX_USER];
+
+ user[0] = 0;
+ strncat(user, name, MAX_USER-1);
+ len = strnlen(user, UT_NAMESIZE);
+ user[len] = 0;
+ if (audit_value_needs_encoding(name, len)) {
+ audit_encode_value(user, name, len);
+ format = "op=%s acct=%s old-seuser=%s old-role=%s old-range=%s new-seuser=%s new-role=%s new-range=%s exe=%s hostname=%s addr=%s terminal=%s res=%s";
+ } else
+ format = "op=%s acct=\"%s\" old-seuser=%s old-role=%s old-range=%s new-seuser=%s new-role=%s new-range=%s exe=%s hostname=%s addr=%s terminal=%s res=%s";
+ snprintf(buf, sizeof(buf), format, op, user,
+ old_seuser && strlen(old_seuser) ? old_seuser : "?",
+ old_role && strlen(old_role) ? old_role : "?",
+ old_range && strlen(old_range) ? old_range : "?",
+ new_seuser && strlen(new_seuser) ? new_seuser : "?",
+ new_role && strlen(new_role) ? new_role : "?",
+ new_range && strlen(new_range) ? new_range : "?",
+ pgname,
+ host && strlen(host) ? host : "?",
+ addrbuf,
+ tty && strlen(tty) ? tty : "?",
+ success
+ );
+ } else
+ snprintf(buf, sizeof(buf),
+ "op=%s id=%u old-seuser=%s old-role=%s old-range=%s new-seuser=%s new-role=%s new-range=%s exe=%s hostname=%s addr=%s terminal=%s res=%s",
+ op, id,
+ old_seuser && strlen(old_seuser) ? old_seuser : "?",
+ old_role && strlen(old_role) ? old_role : "?",
+ old_range && strlen(old_range) ? old_range : "?",
+ new_seuser && strlen(new_seuser) ? new_seuser : "?",
+ new_role && strlen(new_role) ? new_role : "?",
+ new_range && strlen(new_range) ? new_range : "?",
+ pgname,
+ host && strlen(host) ? host : "?",
+ addrbuf,
+ tty && strlen(tty) ? tty : "?",
+ success
+ );
+
+ errno = 0;
+ ret = audit_send_user_message(audit_fd, type, REAL_ERR, buf);
+ if ((ret < 1) && errno == 0)
+ errno = ret;
+ return ret;
+}
+
+/*
+ * This function will log a message to the audit system using a predefined
+ * message format. This function should be used by all console apps that do
+ * not manipulate accounts or groups.
+ *
+ * audit_fd - The fd returned by audit_open
+ * type - type of message, ex: AUDIT_USER_CMD
+ * command - the command line being logged
+ * tty - The tty of the user
+ * result - 1 is "success" and 0 is "failed"
+ *
+ * It returns the sequence number which is > 0 on success or <= 0 on error.
+ */
+int audit_log_user_command(int audit_fd, int type, const char *command,
+ const char *tty, int result)
+{
+ char *p;
+ char buf[MAX_AUDIT_MESSAGE_LENGTH];
+ char commname[PATH_MAX*2];
+ char cwdname[PATH_MAX*2];
+ char ttyname[TTY_PATH];
+ char format[64];
+ const char *success;
+ char *cmd;
+ int ret, cwdenc=0, cmdenc=0;
+ unsigned int len;
+
+ if (audit_fd < 0)
+ return 0;
+
+ if (result)
+ success = "success";
+ else
+ success = "failed";
+
+ if (tty == NULL)
+ tty = _get_tty(ttyname, TTY_PATH);
+ else if (*tty == 0)
+ tty = NULL;
+
+ /* Trim leading spaces */
+ while (*command == ' ')
+ command++;
+
+ cmd = strdup(command);
+ if (cmd == NULL)
+ return -1;
+
+ // We borrow the commname buffer
+ if (getcwd(commname, PATH_MAX) == NULL)
+ strcpy(commname, "?");
+ len = strlen(commname);
+ if (audit_value_needs_encoding(commname, len)) {
+ audit_encode_value(cwdname, commname, len);
+ cwdenc = 1;
+ } else
+ strcpy(cwdname, commname);
+
+ len = strlen(cmd);
+ // Trim the trailing carriage return and spaces
+ while (len && (cmd[len-1] == 0x0A || cmd[len-1] == ' ')) {
+ cmd[len-1] = 0;
+ len--;
+ }
+
+ if (len >= PATH_MAX) {
+ cmd[PATH_MAX] = 0;
+ len = PATH_MAX-1;
+ }
+ if (audit_value_needs_encoding(cmd, len)) {
+ audit_encode_value(commname, cmd, len);
+ cmdenc = 1;
+ }
+ if (cmdenc == 0)
+ strcpy(commname, cmd);
+ free(cmd);
+
+ // Make the format string
+ if (cwdenc)
+ p=stpcpy(format, "cwd=%s ");
+ else
+ p=stpcpy(format, "cwd=\"%s\" ");
+
+ if (cmdenc)
+ p = stpcpy(p, "cmd=%s ");
+ else
+ p = stpcpy(p, "cmd=\"%s\" ");
+
+ strcpy(p, "terminal=%s res=%s");
+
+ // now use the format string to make the event
+ snprintf(buf, sizeof(buf), format,
+ cwdname, commname,
+ tty ? tty : "?",
+ success
+ );
+
+ errno = 0;
+ ret = audit_send_user_message( audit_fd, type, HIDE_IT, buf );
+ if ((ret < 1) && errno == 0)
+ errno = ret;
+ return ret;
+}
+