1185573Srwatson/*- 2191273Srwatson * Copyright (c) 2004-2009 Apple Inc. 3155131Srwatson * All rights reserved. 4155131Srwatson * 5155131Srwatson * Redistribution and use in source and binary forms, with or without 6155131Srwatson * modification, are permitted provided that the following conditions 7155131Srwatson * are met: 8155131Srwatson * 1. Redistributions of source code must retain the above copyright 9155131Srwatson * notice, this list of conditions and the following disclaimer. 10155131Srwatson * 2. Redistributions in binary form must reproduce the above copyright 11155131Srwatson * notice, this list of conditions and the following disclaimer in the 12155131Srwatson * documentation and/or other materials provided with the distribution. 13185573Srwatson * 3. Neither the name of Apple Inc. ("Apple") nor the names of 14155131Srwatson * its contributors may be used to endorse or promote products derived 15155131Srwatson * from this software without specific prior written permission. 16155131Srwatson * 17155131Srwatson * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND 18155131Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19155131Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20155131Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR 21155131Srwatson * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22155131Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23155131Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24155131Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 25155131Srwatson * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 26155131Srwatson * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27155131Srwatson * POSSIBILITY OF SUCH DAMAGE. 28155131Srwatson */ 29155131Srwatson 30155131Srwatson/* 31155131Srwatson * Based on sample code from Marc Majka. 32155131Srwatson */ 33156283Srwatson#include <sys/types.h> 34156283Srwatson 35156283Srwatson#include <config/config.h> 36156283Srwatson#ifdef HAVE_FULL_QUEUE_H 37156283Srwatson#include <sys/queue.h> 38156283Srwatson#else /* !HAVE_FULL_QUEUE_H */ 39156283Srwatson#include <compat/queue.h> 40156283Srwatson#endif /* !HAVE_FULL_QUEUE_H */ 41156283Srwatson 42156283Srwatson#include <bsm/audit_internal.h> 43155131Srwatson#include <bsm/libbsm.h> 44155131Srwatson 45156283Srwatson#include <errno.h> 46159985Srwatson#include <inttypes.h> 47156283Srwatson#include <stdarg.h> 48156283Srwatson#include <string.h> 49156283Srwatson#include <syslog.h> 50156283Srwatson 51156283Srwatson 52155518Srwatson#ifdef __APPLE__ 53155518Srwatson#include <notify.h> 54155131Srwatson/* If 1, assumes a kernel that sends the right notification. */ 55155131Srwatson#define AUDIT_NOTIFICATION_ENABLED 1 56155131Srwatson 57155131Srwatson#if AUDIT_NOTIFICATION_ENABLED 58155131Srwatsonstatic int token = 0; 59155131Srwatson#endif /* AUDIT_NOTIFICATION_ENABLED */ 60155131Srwatson 61191273Srwatsonstatic int au_cond = AUC_UNSET; /* <bsm/audit.h> */ 62155131Srwatson 63155131Srwatsonuint32_t 64155131Srwatsonau_notify_initialize(void) 65155131Srwatson{ 66155131Srwatson#if AUDIT_NOTIFICATION_ENABLED 67168777Srwatson uint32_t status; 68168777Srwatson int ignore_first; 69155131Srwatson 70155131Srwatson status = notify_register_check(__BSM_INTERNAL_NOTIFY_KEY, &token); 71155131Srwatson if (status != NOTIFY_STATUS_OK) 72155131Srwatson return (status); 73155131Srwatson status = notify_check(token, &ignore_first); 74155131Srwatson if (status != NOTIFY_STATUS_OK) 75155131Srwatson return (status); 76155131Srwatson#endif 77155131Srwatson 78191273Srwatson if (audit_get_cond(&au_cond) != 0) { 79155131Srwatson syslog(LOG_ERR, "Initial audit status check failed (%s)", 80155131Srwatson strerror(errno)); 81155131Srwatson if (errno == ENOSYS) /* auditon() unimplemented. */ 82155131Srwatson return (AU_UNIMPL); 83155131Srwatson return (NOTIFY_STATUS_FAILED); /* Is there a better code? */ 84155131Srwatson } 85155131Srwatson return (NOTIFY_STATUS_OK); 86155131Srwatson} 87155131Srwatson 88155131Srwatsonint 89155131Srwatsonau_notify_terminate(void) 90155131Srwatson{ 91155131Srwatson 92155131Srwatson#if AUDIT_NOTIFICATION_ENABLED 93155131Srwatson return ((notify_cancel(token) == NOTIFY_STATUS_OK) ? 0 : -1); 94155131Srwatson#else 95155131Srwatson return (0); 96155131Srwatson#endif 97155131Srwatson} 98155131Srwatson 99155131Srwatson/* 100155131Srwatson * On error of any notify(3) call, reset 'au_cond' to ensure we re-run 101155131Srwatson * au_notify_initialize() next time 'round--but assume auditing is on. This 102155131Srwatson * is a slight performance hit if auditing is off, but at least the system 103155131Srwatson * will behave correctly. The notification calls are unlikely to fail, 104155131Srwatson * anyway. 105155131Srwatson */ 106155131Srwatsonint 107155131Srwatsonau_get_state(void) 108155131Srwatson{ 109155131Srwatson#if AUDIT_NOTIFICATION_ENABLED 110168777Srwatson int did_notify; 111155131Srwatson#endif 112155131Srwatson int status; 113155131Srwatson 114155131Srwatson /* 115155131Srwatson * Don't make the client initialize this set of routines, but take the 116155131Srwatson * slight performance hit by checking ourselves every time. 117155131Srwatson */ 118155131Srwatson if (au_cond == AUC_UNSET) { 119155131Srwatson status = au_notify_initialize(); 120155131Srwatson if (status != NOTIFY_STATUS_OK) { 121155131Srwatson if (status == AU_UNIMPL) 122155131Srwatson return (AU_UNIMPL); 123155131Srwatson return (AUC_AUDITING); 124155131Srwatson } else 125155131Srwatson return (au_cond); 126155131Srwatson } 127155131Srwatson#if AUDIT_NOTIFICATION_ENABLED 128155131Srwatson status = notify_check(token, &did_notify); 129155131Srwatson if (status != NOTIFY_STATUS_OK) { 130155131Srwatson au_cond = AUC_UNSET; 131155131Srwatson return (AUC_AUDITING); 132155131Srwatson } 133155131Srwatson 134155131Srwatson if (did_notify == 0) 135155131Srwatson return (au_cond); 136155131Srwatson#endif 137155131Srwatson 138191273Srwatson if (audit_get_cond(&au_cond) != 0) { 139155131Srwatson /* XXX Reset au_cond to AUC_UNSET? */ 140155131Srwatson syslog(LOG_ERR, "Audit status check failed (%s)", 141155131Srwatson strerror(errno)); 142155131Srwatson if (errno == ENOSYS) /* Function unimplemented. */ 143155131Srwatson return (AU_UNIMPL); 144155131Srwatson return (errno); 145155131Srwatson } 146155131Srwatson 147155131Srwatson switch (au_cond) { 148155131Srwatson case AUC_NOAUDIT: /* Auditing suspended. */ 149155131Srwatson case AUC_DISABLED: /* Auditing shut off. */ 150155131Srwatson return (AUC_NOAUDIT); 151155131Srwatson 152155131Srwatson case AUC_UNSET: /* Uninitialized; shouldn't get here. */ 153155131Srwatson case AUC_AUDITING: /* Audit on. */ 154155131Srwatson default: 155155131Srwatson return (AUC_AUDITING); 156155131Srwatson } 157155131Srwatson} 158155518Srwatson#endif /* !__APPLE__ */ 159155131Srwatson 160155518Srwatsonint 161155518Srwatsoncannot_audit(int val __unused) 162155518Srwatson{ 163155518Srwatson#ifdef __APPLE__ 164155518Srwatson return (!(au_get_state() == AUC_AUDITING)); 165155518Srwatson#else 166191273Srwatson int cond; 167155518Srwatson 168191273Srwatson if (audit_get_cond(&cond) != 0) { 169155518Srwatson if (errno != ENOSYS) { 170155518Srwatson syslog(LOG_ERR, "Audit status check failed (%s)", 171155518Srwatson strerror(errno)); 172155518Srwatson } 173155518Srwatson return (1); 174155518Srwatson } 175191273Srwatson if (cond == AUC_NOAUDIT || cond == AUC_DISABLED) 176155518Srwatson return (1); 177155518Srwatson return (0); 178155518Srwatson#endif /* !__APPLE__ */ 179155518Srwatson} 180