bsm_notify.c revision 293161
167754Smsmith/*- 267754Smsmith * Copyright (c) 2004-2009 Apple Inc. 367754Smsmith * All rights reserved. 467754Smsmith * 567754Smsmith * Redistribution and use in source and binary forms, with or without 667754Smsmith * modification, are permitted provided that the following conditions 7217365Sjkim * are met: 8306536Sjkim * 1. Redistributions of source code must retain the above copyright 970243Smsmith * notice, this list of conditions and the following disclaimer. 1067754Smsmith * 2. Redistributions in binary form must reproduce the above copyright 11217365Sjkim * notice, this list of conditions and the following disclaimer in the 12217365Sjkim * documentation and/or other materials provided with the distribution. 13217365Sjkim * 3. Neither the name of Apple Inc. ("Apple") nor the names of 14217365Sjkim * its contributors may be used to endorse or promote products derived 15217365Sjkim * from this software without specific prior written permission. 16217365Sjkim * 17217365Sjkim * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND 18217365Sjkim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19217365Sjkim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20217365Sjkim * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR 21217365Sjkim * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22217365Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23217365Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24217365Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 2567754Smsmith * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 26217365Sjkim * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27217365Sjkim * POSSIBILITY OF SUCH DAMAGE. 28217365Sjkim */ 2967754Smsmith 30217365Sjkim/* 31217365Sjkim * Based on sample code from Marc Majka. 32217365Sjkim */ 33217365Sjkim#include <sys/types.h> 34217365Sjkim 35217365Sjkim#include <config/config.h> 36217365Sjkim#ifdef HAVE_FULL_QUEUE_H 37217365Sjkim#include <sys/queue.h> 38217365Sjkim#else /* !HAVE_FULL_QUEUE_H */ 39217365Sjkim#include <compat/queue.h> 40217365Sjkim#endif /* !HAVE_FULL_QUEUE_H */ 41217365Sjkim 42217365Sjkim#include <bsm/audit_internal.h> 4367754Smsmith#include <bsm/libbsm.h> 44193341Sjkim 45193341Sjkim#include <errno.h> 46193341Sjkim#include <inttypes.h> 4767754Smsmith#include <stdarg.h> 4867754Smsmith#include <string.h> 4977424Smsmith#include <syslog.h> 5091116Smsmith 5167754Smsmith 5267754Smsmith#ifdef __APPLE__ 5367754Smsmith#include <notify.h> 5467754Smsmith/* If 1, assumes a kernel that sends the right notification. */ 55281075Sdim#define AUDIT_NOTIFICATION_ENABLED 1 56281075Sdim 57281075Sdim#if AUDIT_NOTIFICATION_ENABLED 58281075Sdimstatic int token = 0; 59281075Sdim#endif /* AUDIT_NOTIFICATION_ENABLED */ 60281075Sdim 61281075Sdimstatic int au_cond = AUC_UNSET; /* <bsm/audit.h> */ 62281075Sdim 63281075Sdimuint32_t 64281075Sdimau_notify_initialize(void) 65281075Sdim{ 66281075Sdim#if AUDIT_NOTIFICATION_ENABLED 67281075Sdim uint32_t status; 68281075Sdim int ignore_first; 69281075Sdim 70281075Sdim status = notify_register_check(__BSM_INTERNAL_NOTIFY_KEY, &token); 71281075Sdim if (status != NOTIFY_STATUS_OK) 72281075Sdim return (status); 73281075Sdim status = notify_check(token, &ignore_first); 74281075Sdim if (status != NOTIFY_STATUS_OK) 75281075Sdim return (status); 76281075Sdim#endif 77281075Sdim 78281075Sdim if (audit_get_cond(&au_cond) != 0) { 79281075Sdim syslog(LOG_ERR, "Initial audit status check failed (%s)", 80281075Sdim strerror(errno)); 81281075Sdim if (errno == ENOSYS) /* auditon() unimplemented. */ 82281075Sdim return (AU_UNIMPL); 83281075Sdim return (NOTIFY_STATUS_FAILED); /* Is there a better code? */ 84281075Sdim } 85281075Sdim return (NOTIFY_STATUS_OK); 86281075Sdim} 87281075Sdim 88281075Sdimint 89281075Sdimau_notify_terminate(void) 90281075Sdim{ 91281075Sdim 92151937Sjkim#if AUDIT_NOTIFICATION_ENABLED 93151937Sjkim return ((notify_cancel(token) == NOTIFY_STATUS_OK) ? 0 : -1); 94167802Sjkim#else 95151937Sjkim return (0); 96151937Sjkim#endif 97151937Sjkim} 98151937Sjkim 99151937Sjkim/* 100151937Sjkim * On error of any notify(3) call, reset 'au_cond' to ensure we re-run 101151937Sjkim * au_notify_initialize() next time 'round--but assume auditing is on. This 102253690Sjkim * is a slight performance hit if auditing is off, but at least the system 103151937Sjkim * will behave correctly. The notification calls are unlikely to fail, 104167802Sjkim * anyway. 105151937Sjkim */ 106151937Sjkimint 107151937Sjkimau_get_state(void) 108167802Sjkim{ 109167802Sjkim#if AUDIT_NOTIFICATION_ENABLED 110167802Sjkim int did_notify; 111167802Sjkim#endif 112151937Sjkim int status; 113254745Sjkim 114151937Sjkim /* 115151937Sjkim * Don't make the client initialize this set of routines, but take the 116151937Sjkim * slight performance hit by checking ourselves every time. 117151937Sjkim */ 118151937Sjkim if (au_cond == AUC_UNSET) { 119151937Sjkim status = au_notify_initialize(); 120151937Sjkim if (status != NOTIFY_STATUS_OK) { 121151937Sjkim if (status == AU_UNIMPL) 122167802Sjkim return (AU_UNIMPL); 123151937Sjkim return (AUC_AUDITING); 124151937Sjkim } else 125151937Sjkim return (au_cond); 126151937Sjkim } 127151937Sjkim#if AUDIT_NOTIFICATION_ENABLED 128151937Sjkim status = notify_check(token, &did_notify); 129151937Sjkim if (status != NOTIFY_STATUS_OK) { 130167802Sjkim au_cond = AUC_UNSET; 131151937Sjkim return (AUC_AUDITING); 132151937Sjkim } 133151937Sjkim 134151937Sjkim if (did_notify == 0) 135151937Sjkim return (au_cond); 136151937Sjkim#endif 137151937Sjkim 138151937Sjkim if (audit_get_cond(&au_cond) != 0) { 139151937Sjkim /* XXX Reset au_cond to AUC_UNSET? */ 140151937Sjkim syslog(LOG_ERR, "Audit status check failed (%s)", 141193267Sjkim strerror(errno)); 14267754Smsmith if (errno == ENOSYS) /* Function unimplemented. */ 143167802Sjkim return (AU_UNIMPL); 14467754Smsmith return (errno); 145167802Sjkim } 14667754Smsmith 147167802Sjkim switch (au_cond) { 148241973Sjkim case AUC_NOAUDIT: /* Auditing suspended. */ 14967754Smsmith case AUC_DISABLED: /* Auditing shut off. */ 150167802Sjkim return (AUC_NOAUDIT); 151167802Sjkim 152167802Sjkim case AUC_UNSET: /* Uninitialized; shouldn't get here. */ 15378986Smsmith case AUC_AUDITING: /* Audit on. */ 154167802Sjkim default: 155167802Sjkim return (AUC_AUDITING); 15678986Smsmith } 15778986Smsmith} 15867754Smsmith#endif /* !__APPLE__ */ 15978986Smsmith 160167802Sjkimint 161281687Sjkimcannot_audit(int val __unused) 16278986Smsmith{ 163167802Sjkim#ifdef __APPLE__ 164167802Sjkim return (!(au_get_state() == AUC_AUDITING)); 165167802Sjkim#else 16678986Smsmith int cond; 16778986Smsmith 168167802Sjkim if (audit_get_cond(&cond) != 0) { 16978986Smsmith if (errno != ENOSYS) { 17078986Smsmith syslog(LOG_ERR, "Audit status check failed (%s)", 171167802Sjkim strerror(errno)); 17267754Smsmith } 173167802Sjkim return (1); 174306536Sjkim } 175306536Sjkim if (cond == AUC_NOAUDIT || cond == AUC_DISABLED) 176167802Sjkim return (1); 17784491Smsmith return (0); 178167802Sjkim#endif /* !__APPLE__ */ 179204773Sjkim} 180167802Sjkim