bsm_notify.c revision 156283
1193326Sed/* 2193326Sed * Copyright (c) 2004 Apple Computer, Inc. 3193326Sed * All rights reserved. 4193326Sed * 5193326Sed * Redistribution and use in source and binary forms, with or without 6193326Sed * modification, are permitted provided that the following conditions 7193326Sed * are met: 8193326Sed * 1. Redistributions of source code must retain the above copyright 9193326Sed * notice, this list of conditions and the following disclaimer. 10193326Sed * 2. Redistributions in binary form must reproduce the above copyright 11193326Sed * notice, this list of conditions and the following disclaimer in the 12193326Sed * documentation and/or other materials provided with the distribution. 13193326Sed * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 14193326Sed * its contributors may be used to endorse or promote products derived 15193326Sed * from this software without specific prior written permission. 16193326Sed * 17193326Sed * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND 18193326Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19193326Sed * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20193326Sed * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR 21193326Sed * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22193326Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23193326Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24193326Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 25193326Sed * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 26193326Sed * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27193326Sed * POSSIBILITY OF SUCH DAMAGE. 28193326Sed * 29193326Sed * $P4: //depot/projects/trustedbsd/openbsm/libbsm/bsm_notify.c#11 $ 30193326Sed */ 31193326Sed 32193326Sed/* 33193326Sed * Based on sample code from Marc Majka. 34193326Sed */ 35193326Sed#include <sys/types.h> 36193326Sed 37193326Sed#include <config/config.h> 38193326Sed#ifdef HAVE_FULL_QUEUE_H 39193326Sed#include <sys/queue.h> 40193326Sed#else /* !HAVE_FULL_QUEUE_H */ 41193326Sed#include <compat/queue.h> 42193326Sed#endif /* !HAVE_FULL_QUEUE_H */ 43193326Sed 44193326Sed#include <bsm/audit_internal.h> 45193326Sed#include <bsm/libbsm.h> 46193326Sed 47193326Sed#include <errno.h> 48193326Sed#include <stdint.h> 49193326Sed#include <stdarg.h> 50193326Sed#include <string.h> 51193326Sed#include <syslog.h> 52193326Sed 53193326Sed 54212904Sdim#ifdef __APPLE__ 55193326Sed#include <notify.h> 56193326Sed/* If 1, assumes a kernel that sends the right notification. */ 57193326Sed#define AUDIT_NOTIFICATION_ENABLED 1 58218893Sdim 59193326Sed#if AUDIT_NOTIFICATION_ENABLED 60193326Sedstatic int token = 0; 61193326Sed#endif /* AUDIT_NOTIFICATION_ENABLED */ 62193326Sed 63193326Sedstatic long au_cond = AUC_UNSET; /* <bsm/audit.h> */ 64193326Sed 65206275Srdivackyuint32_t 66234353Sdimau_notify_initialize(void) 67234353Sdim{ 68234353Sdim#if AUDIT_NOTIFICATION_ENABLED 69193326Sed uint32_t status, ignore_first; 70193326Sed 71193326Sed status = notify_register_check(__BSM_INTERNAL_NOTIFY_KEY, &token); 72193326Sed if (status != NOTIFY_STATUS_OK) 73193326Sed return (status); 74193326Sed status = notify_check(token, &ignore_first); 75193326Sed if (status != NOTIFY_STATUS_OK) 76193326Sed return (status); 77193326Sed#endif 78193326Sed 79193326Sed if (auditon(A_GETCOND, &au_cond, sizeof(long)) < 0) { 80193326Sed syslog(LOG_ERR, "Initial audit status check failed (%s)", 81193326Sed strerror(errno)); 82193326Sed if (errno == ENOSYS) /* auditon() unimplemented. */ 83193326Sed return (AU_UNIMPL); 84193326Sed return (NOTIFY_STATUS_FAILED); /* Is there a better code? */ 85193326Sed } 86193326Sed return (NOTIFY_STATUS_OK); 87193326Sed} 88193326Sed 89193326Sedint 90193326Sedau_notify_terminate(void) 91198092Srdivacky{ 92221345Sdim 93221345Sdim#if AUDIT_NOTIFICATION_ENABLED 94239462Sdim return ((notify_cancel(token) == NOTIFY_STATUS_OK) ? 0 : -1); 95239462Sdim#else 96239462Sdim return (0); 97239462Sdim#endif 98239462Sdim} 99221345Sdim 100221345Sdim/* 101223017Sdim * On error of any notify(3) call, reset 'au_cond' to ensure we re-run 102223017Sdim * au_notify_initialize() next time 'round--but assume auditing is on. This 103223017Sdim * is a slight performance hit if auditing is off, but at least the system 104239462Sdim * will behave correctly. The notification calls are unlikely to fail, 105239462Sdim * anyway. 106239462Sdim */ 107239462Sdimint 108221345Sdimau_get_state(void) 109221345Sdim{ 110221345Sdim#if AUDIT_NOTIFICATION_ENABLED 111221345Sdim uint32_t did_notify; 112193326Sed#endif 113193326Sed int status; 114193326Sed 115193326Sed /* 116193326Sed * Don't make the client initialize this set of routines, but take the 117193326Sed * slight performance hit by checking ourselves every time. 118193326Sed */ 119193326Sed if (au_cond == AUC_UNSET) { 120193326Sed status = au_notify_initialize(); 121193326Sed if (status != NOTIFY_STATUS_OK) { 122193326Sed if (status == AU_UNIMPL) 123193326Sed return (AU_UNIMPL); 124210299Sed return (AUC_AUDITING); 125193326Sed } else 126198092Srdivacky return (au_cond); 127193326Sed } 128193326Sed#if AUDIT_NOTIFICATION_ENABLED 129193326Sed status = notify_check(token, &did_notify); 130212904Sdim if (status != NOTIFY_STATUS_OK) { 131212904Sdim au_cond = AUC_UNSET; 132212904Sdim return (AUC_AUDITING); 133212904Sdim } 134212904Sdim 135212904Sdim if (did_notify == 0) 136193326Sed return (au_cond); 137202879Srdivacky#endif 138234353Sdim 139193326Sed if (auditon(A_GETCOND, &au_cond, sizeof(long)) < 0) { 140193326Sed /* XXX Reset au_cond to AUC_UNSET? */ 141193326Sed syslog(LOG_ERR, "Audit status check failed (%s)", 142193326Sed strerror(errno)); 143221345Sdim if (errno == ENOSYS) /* Function unimplemented. */ 144193326Sed return (AU_UNIMPL); 145198092Srdivacky return (errno); 146234353Sdim } 147234353Sdim 148234353Sdim switch (au_cond) { 149198092Srdivacky case AUC_NOAUDIT: /* Auditing suspended. */ 150198092Srdivacky case AUC_DISABLED: /* Auditing shut off. */ 151198092Srdivacky return (AUC_NOAUDIT); 152198092Srdivacky 153198092Srdivacky case AUC_UNSET: /* Uninitialized; shouldn't get here. */ 154193326Sed case AUC_AUDITING: /* Audit on. */ 155208600Srdivacky default: 156193326Sed return (AUC_AUDITING); 157193326Sed } 158193326Sed} 159193326Sed#endif /* !__APPLE__ */ 160207619Srdivacky 161198092Srdivackyint 162193326Sedcannot_audit(int val __unused) 163193326Sed{ 164193326Sed#ifdef __APPLE__ 165193326Sed return (!(au_get_state() == AUC_AUDITING)); 166198092Srdivacky#else 167198092Srdivacky unsigned long au_cond; 168198092Srdivacky 169193326Sed if (auditon(A_GETCOND, &au_cond, sizeof(long)) < 0) { 170193326Sed if (errno != ENOSYS) { 171208600Srdivacky syslog(LOG_ERR, "Audit status check failed (%s)", 172193326Sed strerror(errno)); 173193326Sed } 174193326Sed return (1); 175193326Sed } 176193326Sed if (au_cond == AUC_NOAUDIT || au_cond == AUC_DISABLED) 177193326Sed return (1); 178198092Srdivacky return (0); 179198092Srdivacky#endif /* !__APPLE__ */ 180193326Sed} 181193326Sed