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