1718c8510SRobert Watson /*-
2718c8510SRobert Watson * Copyright (c) 2005 Wayne J. Salamon
3718c8510SRobert Watson * All rights reserved.
4718c8510SRobert Watson *
5718c8510SRobert Watson * This software was developed by Wayne Salamon for the TrustedBSD Project.
6718c8510SRobert Watson *
7718c8510SRobert Watson * Redistribution and use in source and binary forms, with or without
8718c8510SRobert Watson * modification, are permitted provided that the following conditions
9718c8510SRobert Watson * are met:
10718c8510SRobert Watson * 1. Redistributions of source code must retain the above copyright
11718c8510SRobert Watson * notice, this list of conditions and the following disclaimer.
12718c8510SRobert Watson * 2. Redistributions in binary form must reproduce the above copyright
13718c8510SRobert Watson * notice, this list of conditions and the following disclaimer in the
14718c8510SRobert Watson * documentation and/or other materials provided with the distribution.
15718c8510SRobert Watson *
16718c8510SRobert Watson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17718c8510SRobert Watson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18718c8510SRobert Watson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19718c8510SRobert Watson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20718c8510SRobert Watson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21718c8510SRobert Watson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22718c8510SRobert Watson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23718c8510SRobert Watson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24718c8510SRobert Watson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25718c8510SRobert Watson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26718c8510SRobert Watson * SUCH DAMAGE.
27718c8510SRobert Watson */
28718c8510SRobert Watson
29718c8510SRobert Watson #include <sys/param.h>
30718c8510SRobert Watson #include <sys/conf.h>
31718c8510SRobert Watson #include <sys/kernel.h>
32*e2e050c8SConrad Meyer #include <sys/lock.h>
33718c8510SRobert Watson #include <sys/malloc.h>
34*e2e050c8SConrad Meyer #include <sys/mutex.h>
35718c8510SRobert Watson #include <sys/proc.h>
36718c8510SRobert Watson #include <sys/queue.h>
37718c8510SRobert Watson #include <sys/systm.h>
38718c8510SRobert Watson #include <sys/uio.h>
39718c8510SRobert Watson
40718c8510SRobert Watson #include <security/audit/audit.h>
41718c8510SRobert Watson #include <security/audit/audit_private.h>
42718c8510SRobert Watson
43718c8510SRobert Watson /*
44718c8510SRobert Watson * Structures and operations to support the basic character special device
451afabae4SRobert Watson * used to communicate with userland. /dev/audit reliably delivers one-byte
461afabae4SRobert Watson * messages to a listening application (or discards them if there is no
471afabae4SRobert Watson * listening application).
481afabae4SRobert Watson *
491afabae4SRobert Watson * Currently, select/poll are not supported on the trigger device.
50718c8510SRobert Watson */
51718c8510SRobert Watson struct trigger_info {
52718c8510SRobert Watson unsigned int trigger;
53718c8510SRobert Watson TAILQ_ENTRY(trigger_info) list;
54718c8510SRobert Watson };
551afabae4SRobert Watson
56718c8510SRobert Watson static MALLOC_DEFINE(M_AUDITTRIGGER, "audit_trigger", "Audit trigger events");
57718c8510SRobert Watson static struct cdev *audit_dev;
58718c8510SRobert Watson static int audit_isopen = 0;
59718c8510SRobert Watson static TAILQ_HEAD(, trigger_info) trigger_list;
60718c8510SRobert Watson static struct mtx audit_trigger_mtx;
61718c8510SRobert Watson
62718c8510SRobert Watson static int
audit_open(struct cdev * dev,int oflags,int devtype,struct thread * td)63718c8510SRobert Watson audit_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
64718c8510SRobert Watson {
65718c8510SRobert Watson int error;
66718c8510SRobert Watson
67ec914adfSRobert Watson /* Only one process may open the device at a time. */
68718c8510SRobert Watson mtx_lock(&audit_trigger_mtx);
69718c8510SRobert Watson if (!audit_isopen) {
70718c8510SRobert Watson error = 0;
71718c8510SRobert Watson audit_isopen = 1;
72718c8510SRobert Watson } else
73718c8510SRobert Watson error = EBUSY;
74718c8510SRobert Watson mtx_unlock(&audit_trigger_mtx);
75718c8510SRobert Watson
76718c8510SRobert Watson return (error);
77718c8510SRobert Watson }
78718c8510SRobert Watson
79718c8510SRobert Watson static int
audit_close(struct cdev * dev,int fflag,int devtype,struct thread * td)80718c8510SRobert Watson audit_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
81718c8510SRobert Watson {
82718c8510SRobert Watson struct trigger_info *ti;
83718c8510SRobert Watson
84718c8510SRobert Watson /* Flush the queue of pending trigger events. */
85718c8510SRobert Watson mtx_lock(&audit_trigger_mtx);
86718c8510SRobert Watson audit_isopen = 0;
87718c8510SRobert Watson while (!TAILQ_EMPTY(&trigger_list)) {
88718c8510SRobert Watson ti = TAILQ_FIRST(&trigger_list);
89718c8510SRobert Watson TAILQ_REMOVE(&trigger_list, ti, list);
90718c8510SRobert Watson free(ti, M_AUDITTRIGGER);
91718c8510SRobert Watson }
92718c8510SRobert Watson mtx_unlock(&audit_trigger_mtx);
93718c8510SRobert Watson
94718c8510SRobert Watson return (0);
95718c8510SRobert Watson }
96718c8510SRobert Watson
97718c8510SRobert Watson static int
audit_read(struct cdev * dev,struct uio * uio,int ioflag)98718c8510SRobert Watson audit_read(struct cdev *dev, struct uio *uio, int ioflag)
99718c8510SRobert Watson {
100718c8510SRobert Watson int error = 0;
101718c8510SRobert Watson struct trigger_info *ti = NULL;
102718c8510SRobert Watson
103718c8510SRobert Watson mtx_lock(&audit_trigger_mtx);
104718c8510SRobert Watson while (TAILQ_EMPTY(&trigger_list)) {
105718c8510SRobert Watson error = msleep(&trigger_list, &audit_trigger_mtx,
106718c8510SRobert Watson PSOCK | PCATCH, "auditd", 0);
107718c8510SRobert Watson if (error)
108718c8510SRobert Watson break;
109718c8510SRobert Watson }
110718c8510SRobert Watson if (!error) {
111718c8510SRobert Watson ti = TAILQ_FIRST(&trigger_list);
112718c8510SRobert Watson TAILQ_REMOVE(&trigger_list, ti, list);
113718c8510SRobert Watson }
114718c8510SRobert Watson mtx_unlock(&audit_trigger_mtx);
115718c8510SRobert Watson if (!error) {
1168805ca53SRobert Watson error = uiomove(&ti->trigger, sizeof(ti->trigger), uio);
117718c8510SRobert Watson free(ti, M_AUDITTRIGGER);
118718c8510SRobert Watson }
119718c8510SRobert Watson return (error);
120718c8510SRobert Watson }
121718c8510SRobert Watson
122718c8510SRobert Watson static int
audit_write(struct cdev * dev,struct uio * uio,int ioflag)123718c8510SRobert Watson audit_write(struct cdev *dev, struct uio *uio, int ioflag)
124718c8510SRobert Watson {
125718c8510SRobert Watson
126718c8510SRobert Watson /* Communication is kernel->userspace only. */
127718c8510SRobert Watson return (EOPNOTSUPP);
128718c8510SRobert Watson }
129718c8510SRobert Watson
1305ec68199SRobert Watson int
audit_send_trigger(unsigned int trigger)131fb4ed8c9SRobert Watson audit_send_trigger(unsigned int trigger)
132718c8510SRobert Watson {
133718c8510SRobert Watson struct trigger_info *ti;
134718c8510SRobert Watson
135718c8510SRobert Watson ti = malloc(sizeof *ti, M_AUDITTRIGGER, M_WAITOK);
136718c8510SRobert Watson mtx_lock(&audit_trigger_mtx);
1376a9a600bSRobert Watson if (!audit_isopen) {
1386a9a600bSRobert Watson /* If nobody's listening, we ain't talking. */
1396a9a600bSRobert Watson mtx_unlock(&audit_trigger_mtx);
1406a9a600bSRobert Watson free(ti, M_AUDITTRIGGER);
1416a9a600bSRobert Watson return (ENODEV);
1426a9a600bSRobert Watson }
143718c8510SRobert Watson ti->trigger = trigger;
144718c8510SRobert Watson TAILQ_INSERT_TAIL(&trigger_list, ti, list);
145718c8510SRobert Watson wakeup(&trigger_list);
146718c8510SRobert Watson mtx_unlock(&audit_trigger_mtx);
1475ec68199SRobert Watson return (0);
148718c8510SRobert Watson }
149718c8510SRobert Watson
150718c8510SRobert Watson static struct cdevsw audit_cdevsw = {
151718c8510SRobert Watson .d_version = D_VERSION,
152718c8510SRobert Watson .d_open = audit_open,
153718c8510SRobert Watson .d_close = audit_close,
154718c8510SRobert Watson .d_read = audit_read,
155718c8510SRobert Watson .d_write = audit_write,
156718c8510SRobert Watson .d_name = "audit"
157718c8510SRobert Watson };
158718c8510SRobert Watson
159718c8510SRobert Watson void
audit_trigger_init(void)160718c8510SRobert Watson audit_trigger_init(void)
161718c8510SRobert Watson {
162718c8510SRobert Watson
163718c8510SRobert Watson TAILQ_INIT(&trigger_list);
164718c8510SRobert Watson mtx_init(&audit_trigger_mtx, "audit_trigger_mtx", NULL, MTX_DEF);
165718c8510SRobert Watson }
166718c8510SRobert Watson
167718c8510SRobert Watson static void
audit_trigger_cdev_init(void * unused)168718c8510SRobert Watson audit_trigger_cdev_init(void *unused)
169718c8510SRobert Watson {
170718c8510SRobert Watson
171718c8510SRobert Watson /* Create the special device file. */
172718c8510SRobert Watson audit_dev = make_dev(&audit_cdevsw, 0, UID_ROOT, GID_KMEM, 0600,
173718c8510SRobert Watson AUDITDEV_FILENAME);
174718c8510SRobert Watson }
175718c8510SRobert Watson
176718c8510SRobert Watson SYSINIT(audit_trigger_cdev_init, SI_SUB_DRIVERS, SI_ORDER_MIDDLE,
177718c8510SRobert Watson audit_trigger_cdev_init, NULL);
178