1/*
2 * Copyright (c) 2010 Todd C. Miller <Todd.Miller@courtesan.com>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include <config.h>
18
19#include <sys/types.h>
20#include <stdio.h>
21#ifdef STDC_HEADERS
22# include <stdlib.h>
23# include <stddef.h>
24#else
25# ifdef HAVE_STDLIB_H
26#  include <stdlib.h>
27# endif
28#endif /* STDC_HEADERS */
29#include <errno.h>
30#include <fcntl.h>
31#include <string.h>
32#include <libaudit.h>
33
34#include "missing.h"
35#include "error.h"
36#include "alloc.h"
37#include "linux_audit.h"
38
39/*
40 * Open audit connection if possible.
41 * Returns audit fd on success and -1 on failure.
42 */
43static int
44linux_audit_open(void)
45{
46    static int au_fd = -1;
47
48    if (au_fd != -1)
49	return au_fd;
50    au_fd = audit_open();
51    if (au_fd == -1) {
52	/* Kernel may not have audit support. */
53	if (errno != EINVAL && errno != EPROTONOSUPPORT && errno != EAFNOSUPPORT)
54	    error(1, "unable to open audit system");
55    } else {
56	(void)fcntl(au_fd, F_SETFD, FD_CLOEXEC);
57    }
58    return au_fd;
59}
60
61int
62linux_audit_command(char *argv[], int result)
63{
64    int au_fd, rc;
65    char *command, *cp, **av;
66    size_t size, n;
67
68    if ((au_fd = linux_audit_open()) == -1)
69	return -1;
70
71    /* Convert argv to a flat string. */
72    for (size = 0, av = argv; *av != NULL; av++)
73	size += strlen(*av) + 1;
74    command = cp = emalloc(size);
75    for (av = argv; *av != NULL; av++) {
76	n = strlcpy(cp, *av, size - (cp - command));
77	if (n >= size - (cp - command))
78	    errorx(1, "internal error, linux_audit_command() overflow");
79	cp += n;
80	*cp++ = ' ';
81    }
82    *--cp = '\0';
83
84    /* Log command, ignoring ECONNREFUSED on error. */
85    rc = audit_log_user_command(au_fd, AUDIT_USER_CMD, command, NULL, result);
86    if (rc <= 0 && errno != ECONNREFUSED)
87	warning("unable to send audit message");
88
89    efree(command);
90
91    return rc;
92}
93
94#ifdef HAVE_SELINUX
95int
96linux_audit_role_change(const char *old_context,
97    const char *new_context, const char *ttyn)
98{
99    int au_fd, rc;
100    char *message;
101
102    if ((au_fd = linux_audit_open()) == -1)
103	return -1;
104
105    /* audit role change using the same format as newrole(1) */
106    easprintf(&message, "newrole: old-context=%s new-context=%s",
107	old_context, new_context);
108    rc = audit_log_user_message(au_fd, AUDIT_USER_ROLE_CHANGE,
109	message, NULL, NULL, ttyn, 1);
110    if (rc <= 0)
111	warning("unable to send audit message");
112
113    efree(message);
114
115    return rc;
116}
117#endif /* HAVE_SELINUX */
118