1a9643ea8Slogwang /*-
2a9643ea8Slogwang * Copyright (c) 2005 Wayne J. Salamon
3a9643ea8Slogwang * All rights reserved.
4a9643ea8Slogwang *
5a9643ea8Slogwang * This software was developed by Wayne Salamon for the TrustedBSD Project.
6a9643ea8Slogwang *
7a9643ea8Slogwang * Redistribution and use in source and binary forms, with or without
8a9643ea8Slogwang * modification, are permitted provided that the following conditions
9a9643ea8Slogwang * are met:
10a9643ea8Slogwang * 1. Redistributions of source code must retain the above copyright
11a9643ea8Slogwang * notice, this list of conditions and the following disclaimer.
12a9643ea8Slogwang * 2. Redistributions in binary form must reproduce the above copyright
13a9643ea8Slogwang * notice, this list of conditions and the following disclaimer in the
14a9643ea8Slogwang * documentation and/or other materials provided with the distribution.
15a9643ea8Slogwang *
16a9643ea8Slogwang * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17a9643ea8Slogwang * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18a9643ea8Slogwang * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19a9643ea8Slogwang * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20a9643ea8Slogwang * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21a9643ea8Slogwang * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22a9643ea8Slogwang * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23a9643ea8Slogwang * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24a9643ea8Slogwang * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25a9643ea8Slogwang * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26a9643ea8Slogwang * SUCH DAMAGE.
27a9643ea8Slogwang */
28a9643ea8Slogwang
29a9643ea8Slogwang #include <sys/cdefs.h>
30a9643ea8Slogwang __FBSDID("$FreeBSD$");
31a9643ea8Slogwang
32a9643ea8Slogwang #include <sys/param.h>
33a9643ea8Slogwang #include <sys/conf.h>
34a9643ea8Slogwang #include <sys/kernel.h>
35*22ce4affSfengbojiang #include <sys/lock.h>
36a9643ea8Slogwang #include <sys/malloc.h>
37*22ce4affSfengbojiang #include <sys/mutex.h>
38a9643ea8Slogwang #include <sys/proc.h>
39a9643ea8Slogwang #include <sys/queue.h>
40a9643ea8Slogwang #include <sys/systm.h>
41a9643ea8Slogwang #include <sys/uio.h>
42a9643ea8Slogwang
43a9643ea8Slogwang #include <security/audit/audit.h>
44a9643ea8Slogwang #include <security/audit/audit_private.h>
45a9643ea8Slogwang
46a9643ea8Slogwang /*
47a9643ea8Slogwang * Structures and operations to support the basic character special device
48a9643ea8Slogwang * used to communicate with userland. /dev/audit reliably delivers one-byte
49a9643ea8Slogwang * messages to a listening application (or discards them if there is no
50a9643ea8Slogwang * listening application).
51a9643ea8Slogwang *
52a9643ea8Slogwang * Currently, select/poll are not supported on the trigger device.
53a9643ea8Slogwang */
54a9643ea8Slogwang struct trigger_info {
55a9643ea8Slogwang unsigned int trigger;
56a9643ea8Slogwang TAILQ_ENTRY(trigger_info) list;
57a9643ea8Slogwang };
58a9643ea8Slogwang
59a9643ea8Slogwang static MALLOC_DEFINE(M_AUDITTRIGGER, "audit_trigger", "Audit trigger events");
60a9643ea8Slogwang static struct cdev *audit_dev;
61a9643ea8Slogwang static int audit_isopen = 0;
62a9643ea8Slogwang static TAILQ_HEAD(, trigger_info) trigger_list;
63a9643ea8Slogwang static struct mtx audit_trigger_mtx;
64a9643ea8Slogwang
65a9643ea8Slogwang static int
audit_open(struct cdev * dev,int oflags,int devtype,struct thread * td)66a9643ea8Slogwang audit_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
67a9643ea8Slogwang {
68a9643ea8Slogwang int error;
69a9643ea8Slogwang
70a9643ea8Slogwang /* Only one process may open the device at a time. */
71a9643ea8Slogwang mtx_lock(&audit_trigger_mtx);
72a9643ea8Slogwang if (!audit_isopen) {
73a9643ea8Slogwang error = 0;
74a9643ea8Slogwang audit_isopen = 1;
75a9643ea8Slogwang } else
76a9643ea8Slogwang error = EBUSY;
77a9643ea8Slogwang mtx_unlock(&audit_trigger_mtx);
78a9643ea8Slogwang
79a9643ea8Slogwang return (error);
80a9643ea8Slogwang }
81a9643ea8Slogwang
82a9643ea8Slogwang static int
audit_close(struct cdev * dev,int fflag,int devtype,struct thread * td)83a9643ea8Slogwang audit_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
84a9643ea8Slogwang {
85a9643ea8Slogwang struct trigger_info *ti;
86a9643ea8Slogwang
87a9643ea8Slogwang /* Flush the queue of pending trigger events. */
88a9643ea8Slogwang mtx_lock(&audit_trigger_mtx);
89a9643ea8Slogwang audit_isopen = 0;
90a9643ea8Slogwang while (!TAILQ_EMPTY(&trigger_list)) {
91a9643ea8Slogwang ti = TAILQ_FIRST(&trigger_list);
92a9643ea8Slogwang TAILQ_REMOVE(&trigger_list, ti, list);
93a9643ea8Slogwang free(ti, M_AUDITTRIGGER);
94a9643ea8Slogwang }
95a9643ea8Slogwang mtx_unlock(&audit_trigger_mtx);
96a9643ea8Slogwang
97a9643ea8Slogwang return (0);
98a9643ea8Slogwang }
99a9643ea8Slogwang
100a9643ea8Slogwang static int
audit_read(struct cdev * dev,struct uio * uio,int ioflag)101a9643ea8Slogwang audit_read(struct cdev *dev, struct uio *uio, int ioflag)
102a9643ea8Slogwang {
103a9643ea8Slogwang int error = 0;
104a9643ea8Slogwang struct trigger_info *ti = NULL;
105a9643ea8Slogwang
106a9643ea8Slogwang mtx_lock(&audit_trigger_mtx);
107a9643ea8Slogwang while (TAILQ_EMPTY(&trigger_list)) {
108a9643ea8Slogwang error = msleep(&trigger_list, &audit_trigger_mtx,
109a9643ea8Slogwang PSOCK | PCATCH, "auditd", 0);
110a9643ea8Slogwang if (error)
111a9643ea8Slogwang break;
112a9643ea8Slogwang }
113a9643ea8Slogwang if (!error) {
114a9643ea8Slogwang ti = TAILQ_FIRST(&trigger_list);
115a9643ea8Slogwang TAILQ_REMOVE(&trigger_list, ti, list);
116a9643ea8Slogwang }
117a9643ea8Slogwang mtx_unlock(&audit_trigger_mtx);
118a9643ea8Slogwang if (!error) {
119a9643ea8Slogwang error = uiomove(&ti->trigger, sizeof(ti->trigger), uio);
120a9643ea8Slogwang free(ti, M_AUDITTRIGGER);
121a9643ea8Slogwang }
122a9643ea8Slogwang return (error);
123a9643ea8Slogwang }
124a9643ea8Slogwang
125a9643ea8Slogwang static int
audit_write(struct cdev * dev,struct uio * uio,int ioflag)126a9643ea8Slogwang audit_write(struct cdev *dev, struct uio *uio, int ioflag)
127a9643ea8Slogwang {
128a9643ea8Slogwang
129a9643ea8Slogwang /* Communication is kernel->userspace only. */
130a9643ea8Slogwang return (EOPNOTSUPP);
131a9643ea8Slogwang }
132a9643ea8Slogwang
133a9643ea8Slogwang int
audit_send_trigger(unsigned int trigger)134a9643ea8Slogwang audit_send_trigger(unsigned int trigger)
135a9643ea8Slogwang {
136a9643ea8Slogwang struct trigger_info *ti;
137a9643ea8Slogwang
138a9643ea8Slogwang ti = malloc(sizeof *ti, M_AUDITTRIGGER, M_WAITOK);
139a9643ea8Slogwang mtx_lock(&audit_trigger_mtx);
140a9643ea8Slogwang if (!audit_isopen) {
141a9643ea8Slogwang /* If nobody's listening, we ain't talking. */
142a9643ea8Slogwang mtx_unlock(&audit_trigger_mtx);
143a9643ea8Slogwang free(ti, M_AUDITTRIGGER);
144a9643ea8Slogwang return (ENODEV);
145a9643ea8Slogwang }
146a9643ea8Slogwang ti->trigger = trigger;
147a9643ea8Slogwang TAILQ_INSERT_TAIL(&trigger_list, ti, list);
148a9643ea8Slogwang wakeup(&trigger_list);
149a9643ea8Slogwang mtx_unlock(&audit_trigger_mtx);
150a9643ea8Slogwang return (0);
151a9643ea8Slogwang }
152a9643ea8Slogwang
153a9643ea8Slogwang static struct cdevsw audit_cdevsw = {
154a9643ea8Slogwang .d_version = D_VERSION,
155a9643ea8Slogwang .d_open = audit_open,
156a9643ea8Slogwang .d_close = audit_close,
157a9643ea8Slogwang .d_read = audit_read,
158a9643ea8Slogwang .d_write = audit_write,
159a9643ea8Slogwang .d_name = "audit"
160a9643ea8Slogwang };
161a9643ea8Slogwang
162a9643ea8Slogwang void
audit_trigger_init(void)163a9643ea8Slogwang audit_trigger_init(void)
164a9643ea8Slogwang {
165a9643ea8Slogwang
166a9643ea8Slogwang TAILQ_INIT(&trigger_list);
167a9643ea8Slogwang mtx_init(&audit_trigger_mtx, "audit_trigger_mtx", NULL, MTX_DEF);
168a9643ea8Slogwang }
169a9643ea8Slogwang
170a9643ea8Slogwang static void
audit_trigger_cdev_init(void * unused)171a9643ea8Slogwang audit_trigger_cdev_init(void *unused)
172a9643ea8Slogwang {
173a9643ea8Slogwang
174a9643ea8Slogwang /* Create the special device file. */
175a9643ea8Slogwang audit_dev = make_dev(&audit_cdevsw, 0, UID_ROOT, GID_KMEM, 0600,
176a9643ea8Slogwang AUDITDEV_FILENAME);
177a9643ea8Slogwang }
178a9643ea8Slogwang
179a9643ea8Slogwang SYSINIT(audit_trigger_cdev_init, SI_SUB_DRIVERS, SI_ORDER_MIDDLE,
180a9643ea8Slogwang audit_trigger_cdev_init, NULL);
181