audit_trigger.c revision 155192
11541Srgrimes/*-
21541Srgrimes * Copyright (c) 2005 Wayne J. Salamon
31541Srgrimes * All rights reserved.
41541Srgrimes *
51541Srgrimes * This software was developed by Wayne Salamon for the TrustedBSD Project.
61541Srgrimes *
71541Srgrimes * Redistribution and use in source and binary forms, with or without
81541Srgrimes * modification, are permitted provided that the following conditions
91541Srgrimes * are met:
101541Srgrimes * 1. Redistributions of source code must retain the above copyright
111541Srgrimes *    notice, this list of conditions and the following disclaimer.
121541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
131541Srgrimes *    notice, this list of conditions and the following disclaimer in the
141541Srgrimes *    documentation and/or other materials provided with the distribution.
151541Srgrimes *
161541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
171541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
181541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
191541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
201541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
211541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
221541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
231541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
241541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
251541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
261541Srgrimes * SUCH DAMAGE.
271541Srgrimes *
281541Srgrimes * $FreeBSD: head/sys/security/audit/audit_trigger.c 155192 2006-02-01 20:01:18Z rwatson $
291541Srgrimes */
301541Srgrimes
311541Srgrimes#include <sys/param.h>
321541Srgrimes#include <sys/conf.h>
3310939Swollman#include <sys/kernel.h>
3450477Speter#include <sys/malloc.h>
351541Srgrimes#include <sys/proc.h>
361541Srgrimes#include <sys/queue.h>
372169Spaul#include <sys/systm.h>
382169Spaul#include <sys/uio.h>
392169Spaul
407280Swollman#include <security/audit/audit.h>
417280Swollman#include <security/audit/audit_private.h>
421541Srgrimes
431541Srgrimes/*
4421666Swollman * Structures and operations to support the basic character special device
451541Srgrimes * used to communicate with userland.
461541Srgrimes */
471541Srgrimesstruct trigger_info {
481541Srgrimes	unsigned int			trigger;
491541Srgrimes	TAILQ_ENTRY(trigger_info)	list;
501541Srgrimes};
511541Srgrimesstatic MALLOC_DEFINE(M_AUDITTRIGGER, "audit_trigger", "Audit trigger events");
521541Srgrimesstatic struct cdev *audit_dev;
531541Srgrimesstatic int audit_isopen = 0;
541541Srgrimesstatic TAILQ_HEAD(, trigger_info) trigger_list;
551541Srgrimesstatic struct mtx audit_trigger_mtx;
561541Srgrimes
571541Srgrimesstatic int
5820407Swollmanaudit_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
591541Srgrimes{
601541Srgrimes	int error;
611541Srgrimes
621541Srgrimes	// Only one process may open the device at a time
631541Srgrimes	mtx_lock(&audit_trigger_mtx);
641541Srgrimes	if (!audit_isopen) {
651541Srgrimes		error = 0;
661541Srgrimes		audit_isopen = 1;
671541Srgrimes	} else
681541Srgrimes		error = EBUSY;
691541Srgrimes	mtx_unlock(&audit_trigger_mtx);
701541Srgrimes
711541Srgrimes	return (error);
721541Srgrimes}
731541Srgrimes
741541Srgrimesstatic int
751541Srgrimesaudit_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
763865Sswallace{
773865Sswallace	struct trigger_info *ti;
781541Srgrimes
791541Srgrimes	/* Flush the queue of pending trigger events. */
801541Srgrimes	mtx_lock(&audit_trigger_mtx);
811541Srgrimes	audit_isopen = 0;
828876Srgrimes	while (!TAILQ_EMPTY(&trigger_list)) {
831541Srgrimes		ti = TAILQ_FIRST(&trigger_list);
8420407Swollman		TAILQ_REMOVE(&trigger_list, ti, list);
851541Srgrimes		free(ti, M_AUDITTRIGGER);
867090Sbde	}
877090Sbde	mtx_unlock(&audit_trigger_mtx);
881541Srgrimes
891541Srgrimes	return (0);
901541Srgrimes}
911541Srgrimes
921541Srgrimesstatic int
931541Srgrimesaudit_read(struct cdev *dev, struct uio *uio, int ioflag)
941541Srgrimes{
951541Srgrimes	int error = 0;
961541Srgrimes	struct trigger_info *ti = NULL;
971541Srgrimes
981541Srgrimes	mtx_lock(&audit_trigger_mtx);
9920407Swollman	while (TAILQ_EMPTY(&trigger_list)) {
1003865Sswallace		error = msleep(&trigger_list, &audit_trigger_mtx,
1013865Sswallace		    PSOCK | PCATCH, "auditd", 0);
10220407Swollman		if (error)
1031541Srgrimes			break;
10413200Swollman	}
10520407Swollman	if (!error) {
10613200Swollman		ti = TAILQ_FIRST(&trigger_list);
10720407Swollman		TAILQ_REMOVE(&trigger_list, ti, list);
10813200Swollman	}
10913357Sdg	mtx_unlock(&audit_trigger_mtx);
11013200Swollman	if (!error) {
1111541Srgrimes		error = uiomove(ti, sizeof *ti, uio);
1121541Srgrimes		free(ti, M_AUDITTRIGGER);
1131541Srgrimes	}
1141541Srgrimes	return (error);
1151541Srgrimes}
1161541Srgrimes
1171541Srgrimesstatic int
1181541Srgrimesaudit_write(struct cdev *dev, struct uio *uio, int ioflag)
1191541Srgrimes{
1201541Srgrimes
1211541Srgrimes	/* Communication is kernel->userspace only. */
12220407Swollman	return (EOPNOTSUPP);
1231541Srgrimes}
12420407Swollman
1251541Srgrimesvoid
1261541Srgrimessend_trigger(unsigned int trigger)
1271541Srgrimes{
1281541Srgrimes	struct trigger_info *ti;
1291541Srgrimes
1302531Swollman	/* If nobody's listening, we ain't talking. */
1312531Swollman	if (!audit_isopen)
1322531Swollman		return;
1332531Swollman
1342531Swollman	/*
13514622Sfenner	 * XXXAUDIT: Use a condition variable instead of msleep/wakeup?
13614622Sfenner	 */
13714622Sfenner	ti = malloc(sizeof *ti, M_AUDITTRIGGER, M_WAITOK);
13814622Sfenner	mtx_lock(&audit_trigger_mtx);
1392531Swollman	ti->trigger = trigger;
1402531Swollman	TAILQ_INSERT_TAIL(&trigger_list, ti, list);
1412531Swollman	wakeup(&trigger_list);
1421541Srgrimes	mtx_unlock(&audit_trigger_mtx);
1431541Srgrimes}
14421666Swollman
14521666Swollmanstatic struct cdevsw audit_cdevsw = {
14621666Swollman	.d_version =	D_VERSION,
14721666Swollman	.d_open = 	audit_open,
1481541Srgrimes	.d_close = 	audit_close,
1491541Srgrimes	.d_read = 	audit_read,
15021666Swollman	.d_write = 	audit_write,
15121666Swollman	.d_name = 	"audit"
1521541Srgrimes};
15321666Swollman
1541541Srgrimesvoid
1552531Swollmanaudit_trigger_init(void)
1562531Swollman{
1571541Srgrimes
1581541Srgrimes	TAILQ_INIT(&trigger_list);
1591541Srgrimes	mtx_init(&audit_trigger_mtx, "audit_trigger_mtx", NULL, MTX_DEF);
16044078Sdfr}
16144078Sdfr
16244078Sdfrstatic void
16344078Sdfraudit_trigger_cdev_init(void *unused)
16444078Sdfr{
16544078Sdfr
16621666Swollman	/* Create the special device file. */
16721666Swollman	audit_dev = make_dev(&audit_cdevsw, 0, UID_ROOT, GID_KMEM, 0600,
1681541Srgrimes	    AUDITDEV_FILENAME);
1691541Srgrimes}
1701541Srgrimes
1711541SrgrimesSYSINIT(audit_trigger_cdev_init, SI_SUB_DRIVERS, SI_ORDER_MIDDLE,
1721541Srgrimes    audit_trigger_cdev_init, NULL);
1731541Srgrimes