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
29178186Srwatson#include <sys/cdefs.h>
30178186Srwatson__FBSDID("$FreeBSD$");
31178186Srwatson
32155192Srwatson#include <sys/param.h>
33155192Srwatson#include <sys/conf.h>
34155192Srwatson#include <sys/kernel.h>
35155192Srwatson#include <sys/malloc.h>
36155192Srwatson#include <sys/proc.h>
37155192Srwatson#include <sys/queue.h>
38155192Srwatson#include <sys/systm.h>
39155192Srwatson#include <sys/uio.h>
40155192Srwatson
41155192Srwatson#include <security/audit/audit.h>
42155192Srwatson#include <security/audit/audit_private.h>
43155192Srwatson
44155192Srwatson/*
45155192Srwatson * Structures and operations to support the basic character special device
46165604Srwatson * used to communicate with userland.  /dev/audit reliably delivers one-byte
47165604Srwatson * messages to a listening application (or discards them if there is no
48165604Srwatson * listening application).
49165604Srwatson *
50165604Srwatson * Currently, select/poll are not supported on the trigger device.
51155192Srwatson */
52155192Srwatsonstruct trigger_info {
53155192Srwatson	unsigned int			trigger;
54155192Srwatson	TAILQ_ENTRY(trigger_info)	list;
55155192Srwatson};
56165604Srwatson
57155192Srwatsonstatic MALLOC_DEFINE(M_AUDITTRIGGER, "audit_trigger", "Audit trigger events");
58155192Srwatsonstatic struct cdev *audit_dev;
59155192Srwatsonstatic int audit_isopen = 0;
60155192Srwatsonstatic TAILQ_HEAD(, trigger_info) trigger_list;
61155192Srwatsonstatic struct mtx audit_trigger_mtx;
62155192Srwatson
63155192Srwatsonstatic int
64155192Srwatsonaudit_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
65155192Srwatson{
66155192Srwatson	int error;
67155192Srwatson
68159414Srwatson	/* Only one process may open the device at a time. */
69155192Srwatson	mtx_lock(&audit_trigger_mtx);
70155192Srwatson	if (!audit_isopen) {
71155192Srwatson		error = 0;
72155192Srwatson		audit_isopen = 1;
73155192Srwatson	} else
74155192Srwatson		error = EBUSY;
75155192Srwatson	mtx_unlock(&audit_trigger_mtx);
76155192Srwatson
77155192Srwatson	return (error);
78155192Srwatson}
79155192Srwatson
80155192Srwatsonstatic int
81155192Srwatsonaudit_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
82155192Srwatson{
83155192Srwatson	struct trigger_info *ti;
84155192Srwatson
85155192Srwatson	/* Flush the queue of pending trigger events. */
86155192Srwatson	mtx_lock(&audit_trigger_mtx);
87155192Srwatson	audit_isopen = 0;
88155192Srwatson	while (!TAILQ_EMPTY(&trigger_list)) {
89155192Srwatson		ti = TAILQ_FIRST(&trigger_list);
90155192Srwatson		TAILQ_REMOVE(&trigger_list, ti, list);
91155192Srwatson		free(ti, M_AUDITTRIGGER);
92155192Srwatson	}
93155192Srwatson	mtx_unlock(&audit_trigger_mtx);
94155192Srwatson
95155192Srwatson	return (0);
96155192Srwatson}
97155192Srwatson
98155192Srwatsonstatic int
99155192Srwatsonaudit_read(struct cdev *dev, struct uio *uio, int ioflag)
100155192Srwatson{
101155192Srwatson	int error = 0;
102155192Srwatson	struct trigger_info *ti = NULL;
103155192Srwatson
104155192Srwatson	mtx_lock(&audit_trigger_mtx);
105155192Srwatson	while (TAILQ_EMPTY(&trigger_list)) {
106155192Srwatson		error = msleep(&trigger_list, &audit_trigger_mtx,
107155192Srwatson		    PSOCK | PCATCH, "auditd", 0);
108155192Srwatson		if (error)
109155192Srwatson			break;
110155192Srwatson	}
111155192Srwatson	if (!error) {
112155192Srwatson		ti = TAILQ_FIRST(&trigger_list);
113155192Srwatson		TAILQ_REMOVE(&trigger_list, ti, list);
114155192Srwatson	}
115155192Srwatson	mtx_unlock(&audit_trigger_mtx);
116155192Srwatson	if (!error) {
117176749Srwatson		error = uiomove(&ti->trigger, sizeof(ti->trigger), uio);
118155192Srwatson		free(ti, M_AUDITTRIGGER);
119155192Srwatson	}
120155192Srwatson	return (error);
121155192Srwatson}
122155192Srwatson
123155192Srwatsonstatic int
124155192Srwatsonaudit_write(struct cdev *dev, struct uio *uio, int ioflag)
125155192Srwatson{
126155192Srwatson
127155192Srwatson	/* Communication is kernel->userspace only. */
128155192Srwatson	return (EOPNOTSUPP);
129155192Srwatson}
130155192Srwatson
131156845Srwatsonint
132176686Srwatsonaudit_send_trigger(unsigned int trigger)
133155192Srwatson{
134155192Srwatson	struct trigger_info *ti;
135155192Srwatson
136155192Srwatson	ti = malloc(sizeof *ti, M_AUDITTRIGGER, M_WAITOK);
137155192Srwatson	mtx_lock(&audit_trigger_mtx);
138170687Srwatson	if (!audit_isopen) {
139170687Srwatson		/* If nobody's listening, we ain't talking. */
140170687Srwatson		mtx_unlock(&audit_trigger_mtx);
141170687Srwatson		free(ti, M_AUDITTRIGGER);
142170687Srwatson		return (ENODEV);
143170687Srwatson	}
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,
153180709Srwatson	.d_open =	audit_open,
154180709Srwatson	.d_close =	audit_close,
155180709Srwatson	.d_read =	audit_read,
156180709Srwatson	.d_write =	audit_write,
157180709Srwatson	.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