audit_trigger.c revision 165604
1155192Srwatson/*-
2155192Srwatson * Copyright (c) 2005 Wayne J. Salamon
3155192Srwatson * All rights reserved.
4155192Srwatson *
5155192Srwatson * This software was developed by Wayne Salamon for the TrustedBSD Project.
6155192Srwatson *
7155192Srwatson * Redistribution and use in source and binary forms, with or without
8155192Srwatson * modification, are permitted provided that the following conditions
9155192Srwatson * are met:
10155192Srwatson * 1. Redistributions of source code must retain the above copyright
11155192Srwatson *    notice, this list of conditions and the following disclaimer.
12155192Srwatson * 2. Redistributions in binary form must reproduce the above copyright
13155192Srwatson *    notice, this list of conditions and the following disclaimer in the
14155192Srwatson *    documentation and/or other materials provided with the distribution.
15155192Srwatson *
16155192Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17155192Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18155192Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19155192Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20155192Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21155192Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22155192Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23155192Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24155192Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25155192Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26155192Srwatson * SUCH DAMAGE.
27155192Srwatson *
28155192Srwatson * $FreeBSD: head/sys/security/audit/audit_trigger.c 165604 2006-12-28 22:18:43Z rwatson $
29155192Srwatson */
30155192Srwatson
31155192Srwatson#include <sys/param.h>
32155192Srwatson#include <sys/conf.h>
33155192Srwatson#include <sys/kernel.h>
34155192Srwatson#include <sys/malloc.h>
35155192Srwatson#include <sys/proc.h>
36155192Srwatson#include <sys/queue.h>
37155192Srwatson#include <sys/systm.h>
38155192Srwatson#include <sys/uio.h>
39155192Srwatson
40155192Srwatson#include <security/audit/audit.h>
41155192Srwatson#include <security/audit/audit_private.h>
42155192Srwatson
43155192Srwatson/*
44155192Srwatson * Structures and operations to support the basic character special device
45165604Srwatson * used to communicate with userland.  /dev/audit reliably delivers one-byte
46165604Srwatson * messages to a listening application (or discards them if there is no
47165604Srwatson * listening application).
48165604Srwatson *
49165604Srwatson * Currently, select/poll are not supported on the trigger device.
50155192Srwatson */
51155192Srwatsonstruct trigger_info {
52155192Srwatson	unsigned int			trigger;
53155192Srwatson	TAILQ_ENTRY(trigger_info)	list;
54155192Srwatson};
55165604Srwatson
56155192Srwatsonstatic MALLOC_DEFINE(M_AUDITTRIGGER, "audit_trigger", "Audit trigger events");
57155192Srwatsonstatic struct cdev *audit_dev;
58155192Srwatsonstatic int audit_isopen = 0;
59155192Srwatsonstatic TAILQ_HEAD(, trigger_info) trigger_list;
60155192Srwatsonstatic struct mtx audit_trigger_mtx;
61155192Srwatson
62155192Srwatsonstatic int
63155192Srwatsonaudit_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
64155192Srwatson{
65155192Srwatson	int error;
66155192Srwatson
67159414Srwatson	/* Only one process may open the device at a time. */
68155192Srwatson	mtx_lock(&audit_trigger_mtx);
69155192Srwatson	if (!audit_isopen) {
70155192Srwatson		error = 0;
71155192Srwatson		audit_isopen = 1;
72155192Srwatson	} else
73155192Srwatson		error = EBUSY;
74155192Srwatson	mtx_unlock(&audit_trigger_mtx);
75155192Srwatson
76155192Srwatson	return (error);
77155192Srwatson}
78155192Srwatson
79155192Srwatsonstatic int
80155192Srwatsonaudit_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
81155192Srwatson{
82155192Srwatson	struct trigger_info *ti;
83155192Srwatson
84155192Srwatson	/* Flush the queue of pending trigger events. */
85155192Srwatson	mtx_lock(&audit_trigger_mtx);
86155192Srwatson	audit_isopen = 0;
87155192Srwatson	while (!TAILQ_EMPTY(&trigger_list)) {
88155192Srwatson		ti = TAILQ_FIRST(&trigger_list);
89155192Srwatson		TAILQ_REMOVE(&trigger_list, ti, list);
90155192Srwatson		free(ti, M_AUDITTRIGGER);
91155192Srwatson	}
92155192Srwatson	mtx_unlock(&audit_trigger_mtx);
93155192Srwatson
94155192Srwatson	return (0);
95155192Srwatson}
96155192Srwatson
97155192Srwatsonstatic int
98155192Srwatsonaudit_read(struct cdev *dev, struct uio *uio, int ioflag)
99155192Srwatson{
100155192Srwatson	int error = 0;
101155192Srwatson	struct trigger_info *ti = NULL;
102155192Srwatson
103155192Srwatson	mtx_lock(&audit_trigger_mtx);
104155192Srwatson	while (TAILQ_EMPTY(&trigger_list)) {
105155192Srwatson		error = msleep(&trigger_list, &audit_trigger_mtx,
106155192Srwatson		    PSOCK | PCATCH, "auditd", 0);
107155192Srwatson		if (error)
108155192Srwatson			break;
109155192Srwatson	}
110155192Srwatson	if (!error) {
111155192Srwatson		ti = TAILQ_FIRST(&trigger_list);
112155192Srwatson		TAILQ_REMOVE(&trigger_list, ti, list);
113155192Srwatson	}
114155192Srwatson	mtx_unlock(&audit_trigger_mtx);
115155192Srwatson	if (!error) {
116155192Srwatson		error = uiomove(ti, sizeof *ti, uio);
117155192Srwatson		free(ti, M_AUDITTRIGGER);
118155192Srwatson	}
119155192Srwatson	return (error);
120155192Srwatson}
121155192Srwatson
122155192Srwatsonstatic int
123155192Srwatsonaudit_write(struct cdev *dev, struct uio *uio, int ioflag)
124155192Srwatson{
125155192Srwatson
126155192Srwatson	/* Communication is kernel->userspace only. */
127155192Srwatson	return (EOPNOTSUPP);
128155192Srwatson}
129155192Srwatson
130156845Srwatsonint
131155192Srwatsonsend_trigger(unsigned int trigger)
132155192Srwatson{
133155192Srwatson	struct trigger_info *ti;
134155192Srwatson
135155192Srwatson	/* If nobody's listening, we ain't talking. */
136155192Srwatson	if (!audit_isopen)
137156845Srwatson		return (ENODEV);
138155192Srwatson
139155192Srwatson	/*
140165604Srwatson	 * Note: Use a condition variable instead of msleep/wakeup?
141155192Srwatson	 */
142155192Srwatson	ti = malloc(sizeof *ti, M_AUDITTRIGGER, M_WAITOK);
143155192Srwatson	mtx_lock(&audit_trigger_mtx);
144155192Srwatson	ti->trigger = trigger;
145155192Srwatson	TAILQ_INSERT_TAIL(&trigger_list, ti, list);
146155192Srwatson	wakeup(&trigger_list);
147155192Srwatson	mtx_unlock(&audit_trigger_mtx);
148156845Srwatson	return (0);
149155192Srwatson}
150155192Srwatson
151155192Srwatsonstatic struct cdevsw audit_cdevsw = {
152155192Srwatson	.d_version =	D_VERSION,
153155192Srwatson	.d_open = 	audit_open,
154155192Srwatson	.d_close = 	audit_close,
155155192Srwatson	.d_read = 	audit_read,
156155192Srwatson	.d_write = 	audit_write,
157155192Srwatson	.d_name = 	"audit"
158155192Srwatson};
159155192Srwatson
160155192Srwatsonvoid
161155192Srwatsonaudit_trigger_init(void)
162155192Srwatson{
163155192Srwatson
164155192Srwatson	TAILQ_INIT(&trigger_list);
165155192Srwatson	mtx_init(&audit_trigger_mtx, "audit_trigger_mtx", NULL, MTX_DEF);
166155192Srwatson}
167155192Srwatson
168155192Srwatsonstatic void
169155192Srwatsonaudit_trigger_cdev_init(void *unused)
170155192Srwatson{
171155192Srwatson
172155192Srwatson	/* Create the special device file. */
173155192Srwatson	audit_dev = make_dev(&audit_cdevsw, 0, UID_ROOT, GID_KMEM, 0600,
174155192Srwatson	    AUDITDEV_FILENAME);
175155192Srwatson}
176155192Srwatson
177155192SrwatsonSYSINIT(audit_trigger_cdev_init, SI_SUB_DRIVERS, SI_ORDER_MIDDLE,
178155192Srwatson    audit_trigger_cdev_init, NULL);
179