bsm_wrappers.c revision 168777
1155131Srwatson/* 2155131Srwatson * Copyright (c) 2004 Apple Computer, 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. 13155131Srwatson * 3. Neither the name of Apple Computer, 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 * 29168777Srwatson * $P4: //depot/projects/trustedbsd/openbsm/libbsm/bsm_wrappers.c#24 $ 30155131Srwatson */ 31155131Srwatson 32155518Srwatson#ifdef __APPLE__ 33155518Srwatson#define _SYS_AUDIT_H /* Prevent include of sys/audit.h. */ 34155518Srwatson#endif 35155518Srwatson 36155131Srwatson#include <sys/param.h> 37155131Srwatson#include <sys/stat.h> 38156283Srwatson 39156283Srwatson#ifdef __APPLE__ 40156283Srwatson#include <sys/queue.h> /* Our bsm/audit.h doesn't include queue.h. */ 41156283Srwatson#endif 42156283Srwatson 43155131Srwatson#include <sys/sysctl.h> 44155131Srwatson 45155131Srwatson#include <bsm/libbsm.h> 46155131Srwatson 47155131Srwatson#include <unistd.h> 48155131Srwatson#include <syslog.h> 49159248Srwatson#include <stdarg.h> 50155131Srwatson#include <string.h> 51155131Srwatson#include <errno.h> 52155131Srwatson 53155131Srwatson/* These are not advertised in libbsm.h */ 54155131Srwatsonint audit_set_terminal_port(dev_t *p); 55155131Srwatsonint audit_set_terminal_host(uint32_t *m); 56155131Srwatson 57159248Srwatson/* 58159248Srwatson * General purpose audit submission mechanism for userspace. 59159248Srwatson */ 60155131Srwatsonint 61159248Srwatsonaudit_submit(short au_event, au_id_t auid, char status, 62159248Srwatson int reterr, const char *fmt, ...) 63159248Srwatson{ 64159248Srwatson char text[MAX_AUDITSTRING_LEN]; 65159248Srwatson token_t *token; 66159248Srwatson long acond; 67159248Srwatson va_list ap; 68159248Srwatson pid_t pid; 69168777Srwatson int error, afd, subj_ex; 70159248Srwatson struct auditinfo ai; 71168777Srwatson struct auditinfo_addr aia; 72159248Srwatson 73159248Srwatson if (auditon(A_GETCOND, &acond, sizeof(acond)) < 0) { 74159248Srwatson /* 75159248Srwatson * If auditon(2) returns ENOSYS, then audit has not been 76159248Srwatson * compiled into the kernel, so just return. 77159248Srwatson */ 78159248Srwatson if (errno == ENOSYS) 79159248Srwatson return (0); 80159248Srwatson error = errno; 81159248Srwatson syslog(LOG_AUTH | LOG_ERR, "audit: auditon failed: %s", 82159248Srwatson strerror(errno)); 83159248Srwatson errno = error; 84159248Srwatson return (-1); 85159248Srwatson } 86159248Srwatson if (acond == AUC_NOAUDIT) 87159248Srwatson return (0); 88168777Srwatson /* XXXCSJP we should be doing a pre-select here */ 89159248Srwatson afd = au_open(); 90159248Srwatson if (afd < 0) { 91159248Srwatson error = errno; 92159248Srwatson syslog(LOG_AUTH | LOG_ERR, "audit: au_open failed: %s", 93159248Srwatson strerror(errno)); 94159248Srwatson errno = error; 95159248Srwatson return (-1); 96159248Srwatson } 97168777Srwatson /* 98168777Srwatson * Some operating systems do not have getaudit_addr(2) implemented 99168777Srwatson * yet. So we try to use getaudit(2) first, if the subject is 100168777Srwatson * using IPv6, then we will have to try getaudit_addr(2). Failing 101168777Srwatson * this, we return error. 102168777Srwatson */ 103168777Srwatson subj_ex = 0; 104168777Srwatson error = getaudit(&ai); 105168777Srwatson if (error < 0 && errno == E2BIG) { 106168777Srwatson error = getaudit_addr(&aia, sizeof(aia)); 107168777Srwatson if (error == 0) 108168777Srwatson subj_ex = 1; 109168777Srwatson } 110168777Srwatson if (error < 0) { 111159248Srwatson error = errno; 112159248Srwatson syslog(LOG_AUTH | LOG_ERR, "audit: getaudit failed: %s", 113159248Srwatson strerror(errno)); 114159248Srwatson errno = error; 115159248Srwatson return (-1); 116159248Srwatson } 117159248Srwatson pid = getpid(); 118168777Srwatson if (subj_ex == 0) 119168777Srwatson token = au_to_subject32(auid, geteuid(), getegid(), 120168777Srwatson getuid(), getgid(), pid, pid, &ai.ai_termid); 121168777Srwatson else 122168777Srwatson token = au_to_subject_ex(auid, geteuid(), getegid(), 123168777Srwatson getuid(), getgid(), pid, pid, &aia.ai_termid); 124159248Srwatson if (token == NULL) { 125159248Srwatson syslog(LOG_AUTH | LOG_ERR, 126159248Srwatson "audit: unable to build subject token"); 127159248Srwatson (void) au_close(afd, AU_TO_NO_WRITE, au_event); 128159248Srwatson errno = EPERM; 129159248Srwatson return (-1); 130159248Srwatson } 131159248Srwatson if (au_write(afd, token) < 0) { 132159248Srwatson error = errno; 133159248Srwatson syslog(LOG_AUTH | LOG_ERR, 134159248Srwatson "audit: au_write failed: %s", strerror(errno)); 135159248Srwatson (void) au_close(afd, AU_TO_NO_WRITE, au_event); 136159248Srwatson errno = error; 137159248Srwatson return (-1); 138159248Srwatson } 139159248Srwatson if (fmt != NULL) { 140159248Srwatson va_start(ap, fmt); 141159248Srwatson (void) vsnprintf(text, MAX_AUDITSTRING_LEN, fmt, ap); 142159248Srwatson va_end(ap); 143159248Srwatson token = au_to_text(text); 144159248Srwatson if (token == NULL) { 145159248Srwatson syslog(LOG_AUTH | LOG_ERR, 146159248Srwatson "audit: failed to generate text token"); 147159248Srwatson (void) au_close(afd, AU_TO_NO_WRITE, au_event); 148159248Srwatson errno = EPERM; 149159248Srwatson return (-1); 150159248Srwatson } 151159248Srwatson if (au_write(afd, token) < 0) { 152159248Srwatson error = errno; 153159248Srwatson syslog(LOG_AUTH | LOG_ERR, 154159248Srwatson "audit: au_write failed: %s", strerror(errno)); 155159248Srwatson (void) au_close(afd, AU_TO_NO_WRITE, au_event); 156159248Srwatson errno = error; 157159248Srwatson return (-1); 158159248Srwatson } 159159248Srwatson } 160159248Srwatson token = au_to_return32(status, reterr); 161159248Srwatson if (token == NULL) { 162159248Srwatson syslog(LOG_AUTH | LOG_ERR, 163159248Srwatson "audit: enable to build return token"); 164159248Srwatson (void) au_close(afd, AU_TO_NO_WRITE, au_event); 165159248Srwatson errno = EPERM; 166159248Srwatson return (-1); 167159248Srwatson } 168159248Srwatson if (au_write(afd, token) < 0) { 169159248Srwatson error = errno; 170159248Srwatson syslog(LOG_AUTH | LOG_ERR, 171159248Srwatson "audit: au_write failed: %s", strerror(errno)); 172159248Srwatson (void) au_close(afd, AU_TO_NO_WRITE, au_event); 173159248Srwatson errno = error; 174159248Srwatson return (-1); 175159248Srwatson } 176159248Srwatson if (au_close(afd, AU_TO_WRITE, au_event) < 0) { 177159248Srwatson error = errno; 178159248Srwatson syslog(LOG_AUTH | LOG_ERR, "audit: record not committed"); 179159248Srwatson errno = error; 180159248Srwatson return (-1); 181159248Srwatson } 182159248Srwatson return (0); 183159248Srwatson} 184159248Srwatson 185159248Srwatsonint 186155131Srwatsonaudit_set_terminal_port(dev_t *p) 187155131Srwatson{ 188155131Srwatson struct stat st; 189155131Srwatson 190155131Srwatson if (p == NULL) 191155131Srwatson return (kAUBadParamErr); 192155131Srwatson 193156283Srwatson#ifdef NODEV 194155131Srwatson *p = NODEV; 195156283Srwatson#else 196156283Srwatson *p = -1; 197156283Srwatson#endif 198155131Srwatson 199155131Srwatson /* for /usr/bin/login, try fstat() first */ 200155131Srwatson if (fstat(STDIN_FILENO, &st) != 0) { 201155131Srwatson if (errno != EBADF) { 202155131Srwatson syslog(LOG_ERR, "fstat() failed (%s)", 203155131Srwatson strerror(errno)); 204155131Srwatson return (kAUStatErr); 205155131Srwatson } 206155131Srwatson if (stat("/dev/console", &st) != 0) { 207155131Srwatson syslog(LOG_ERR, "stat() failed (%s)", 208155131Srwatson strerror(errno)); 209155131Srwatson return (kAUStatErr); 210155131Srwatson } 211155131Srwatson } 212155131Srwatson *p = st.st_rdev; 213155131Srwatson return (kAUNoErr); 214155131Srwatson} 215155131Srwatson 216155131Srwatsonint 217155131Srwatsonaudit_set_terminal_host(uint32_t *m) 218155131Srwatson{ 219156283Srwatson 220156283Srwatson#ifdef KERN_HOSTID 221155131Srwatson int name[2] = { CTL_KERN, KERN_HOSTID }; 222155131Srwatson size_t len; 223155131Srwatson 224155131Srwatson if (m == NULL) 225155131Srwatson return (kAUBadParamErr); 226155131Srwatson *m = 0; 227155131Srwatson len = sizeof(*m); 228155131Srwatson if (sysctl(name, 2, m, &len, NULL, 0) != 0) { 229155131Srwatson syslog(LOG_ERR, "sysctl() failed (%s)", strerror(errno)); 230155131Srwatson return (kAUSysctlErr); 231155131Srwatson } 232155131Srwatson return (kAUNoErr); 233156283Srwatson#else 234156283Srwatson *m = -1; 235156283Srwatson return (kAUNoErr); 236156283Srwatson#endif 237155131Srwatson} 238155131Srwatson 239155131Srwatsonint 240155131Srwatsonaudit_set_terminal_id(au_tid_t *tid) 241155131Srwatson{ 242155131Srwatson int ret; 243155131Srwatson 244155131Srwatson if (tid == NULL) 245155131Srwatson return (kAUBadParamErr); 246155131Srwatson if ((ret = audit_set_terminal_port(&tid->port)) != kAUNoErr) 247155131Srwatson return (ret); 248155131Srwatson return (audit_set_terminal_host(&tid->machine)); 249155131Srwatson} 250155131Srwatson 251155131Srwatson/* 252155131Srwatson * This is OK for those callers who have only one token to write. If you have 253155131Srwatson * multiple tokens that logically form part of the same audit record, you need 254155131Srwatson * to use the existing au_open()/au_write()/au_close() API: 255155131Srwatson * 256155131Srwatson * aufd = au_open(); 257155131Srwatson * tok = au_to_random_token_1(...); 258155131Srwatson * au_write(aufd, tok); 259155131Srwatson * tok = au_to_random_token_2(...); 260155131Srwatson * au_write(aufd, tok); 261155131Srwatson * ... 262159248Srwatson * au_close(aufd, AU_TO_WRITE, AUE_your_event_type); 263155131Srwatson * 264155131Srwatson * Assumes, like all wrapper calls, that the caller has previously checked 265155131Srwatson * that auditing is enabled via the audit_get_state() call. 266155131Srwatson * 267155131Srwatson * XXX: Should be more robust against bad arguments. 268155131Srwatson */ 269155131Srwatsonint 270155131Srwatsonaudit_write(short event_code, token_t *subject, token_t *misctok, char retval, 271155131Srwatson int errcode) 272155131Srwatson{ 273155131Srwatson int aufd; 274155131Srwatson char *func = "audit_write()"; 275155131Srwatson token_t *rettok; 276155131Srwatson 277155131Srwatson if ((aufd = au_open()) == -1) { 278155131Srwatson au_free_token(subject); 279155131Srwatson au_free_token(misctok); 280155131Srwatson syslog(LOG_ERR, "%s: au_open() failed", func); 281155131Srwatson return (kAUOpenErr); 282155131Srwatson } 283155131Srwatson 284155131Srwatson /* Save subject. */ 285155131Srwatson if (subject && au_write(aufd, subject) == -1) { 286155131Srwatson au_free_token(subject); 287155131Srwatson au_free_token(misctok); 288159248Srwatson (void)au_close(aufd, AU_TO_WRITE, event_code); 289155131Srwatson syslog(LOG_ERR, "%s: write of subject failed", func); 290155131Srwatson return (kAUWriteSubjectTokErr); 291155131Srwatson } 292155131Srwatson 293155131Srwatson /* Save the event-specific token. */ 294155131Srwatson if (misctok && au_write(aufd, misctok) == -1) { 295155131Srwatson au_free_token(misctok); 296159248Srwatson (void)au_close(aufd, AU_TO_NO_WRITE, event_code); 297155131Srwatson syslog(LOG_ERR, "%s: write of caller token failed", func); 298155131Srwatson return (kAUWriteCallerTokErr); 299155131Srwatson } 300155131Srwatson 301155131Srwatson /* Tokenize and save the return value. */ 302155131Srwatson if ((rettok = au_to_return32(retval, errcode)) == NULL) { 303159248Srwatson (void)au_close(aufd, AU_TO_NO_WRITE, event_code); 304155131Srwatson syslog(LOG_ERR, "%s: au_to_return32() failed", func); 305155131Srwatson return (kAUMakeReturnTokErr); 306155131Srwatson } 307155131Srwatson 308155131Srwatson if (au_write(aufd, rettok) == -1) { 309155131Srwatson au_free_token(rettok); 310159248Srwatson (void)au_close(aufd, AU_TO_NO_WRITE, event_code); 311155131Srwatson syslog(LOG_ERR, "%s: write of return code failed", func); 312155131Srwatson return (kAUWriteReturnTokErr); 313155131Srwatson } 314155131Srwatson 315155131Srwatson /* 316159248Srwatson * We assume the caller wouldn't have bothered with this 317155131Srwatson * function if it hadn't already decided to keep the record. 318155131Srwatson */ 319159248Srwatson if (au_close(aufd, AU_TO_WRITE, event_code) < 0) { 320155131Srwatson syslog(LOG_ERR, "%s: au_close() failed", func); 321155131Srwatson return (kAUCloseErr); 322155131Srwatson } 323155131Srwatson 324155131Srwatson return (kAUNoErr); 325155131Srwatson} 326155131Srwatson 327155131Srwatson/* 328155131Srwatson * Same caveats as audit_write(). In addition, this function explicitly 329155131Srwatson * assumes success; use audit_write_failure() on error. 330155131Srwatson */ 331155131Srwatsonint 332155131Srwatsonaudit_write_success(short event_code, token_t *tok, au_id_t auid, uid_t euid, 333155131Srwatson gid_t egid, uid_t ruid, gid_t rgid, pid_t pid, au_asid_t sid, 334155131Srwatson au_tid_t *tid) 335155131Srwatson{ 336155131Srwatson char *func = "audit_write_success()"; 337155131Srwatson token_t *subject = NULL; 338155131Srwatson 339155131Srwatson /* Tokenize and save subject. */ 340155131Srwatson subject = au_to_subject32(auid, euid, egid, ruid, rgid, pid, sid, 341155131Srwatson tid); 342155131Srwatson if (subject == NULL) { 343155131Srwatson syslog(LOG_ERR, "%s: au_to_subject32() failed", func); 344155131Srwatson return kAUMakeSubjectTokErr; 345155131Srwatson } 346155131Srwatson 347155131Srwatson return (audit_write(event_code, subject, tok, 0, 0)); 348155131Srwatson} 349155131Srwatson 350155131Srwatson/* 351155131Srwatson * Same caveats as audit_write(). In addition, this function explicitly 352155131Srwatson * assumes success; use audit_write_failure_self() on error. 353155131Srwatson */ 354155131Srwatsonint 355155131Srwatsonaudit_write_success_self(short event_code, token_t *tok) 356155131Srwatson{ 357155131Srwatson token_t *subject; 358155131Srwatson char *func = "audit_write_success_self()"; 359155131Srwatson 360155131Srwatson if ((subject = au_to_me()) == NULL) { 361155131Srwatson syslog(LOG_ERR, "%s: au_to_me() failed", func); 362155131Srwatson return (kAUMakeSubjectTokErr); 363155131Srwatson } 364155131Srwatson 365155131Srwatson return (audit_write(event_code, subject, tok, 0, 0)); 366155131Srwatson} 367155131Srwatson 368155131Srwatson/* 369155131Srwatson * Same caveats as audit_write(). In addition, this function explicitly 370155131Srwatson * assumes failure; use audit_write_success() otherwise. 371155131Srwatson * 372155131Srwatson * XXX This should let the caller pass an error return value rather than 373155131Srwatson * hard-coding -1. 374155131Srwatson */ 375155131Srwatsonint 376155131Srwatsonaudit_write_failure(short event_code, char *errmsg, int errcode, au_id_t auid, 377155131Srwatson uid_t euid, gid_t egid, uid_t ruid, gid_t rgid, pid_t pid, au_asid_t sid, 378155131Srwatson au_tid_t *tid) 379155131Srwatson{ 380155131Srwatson char *func = "audit_write_failure()"; 381155131Srwatson token_t *subject, *errtok; 382155131Srwatson 383155131Srwatson subject = au_to_subject32(auid, euid, egid, ruid, rgid, pid, sid, tid); 384155131Srwatson if (subject == NULL) { 385155131Srwatson syslog(LOG_ERR, "%s: au_to_subject32() failed", func); 386155131Srwatson return (kAUMakeSubjectTokErr); 387155131Srwatson } 388155131Srwatson 389155131Srwatson /* tokenize and save the error message */ 390155131Srwatson if ((errtok = au_to_text(errmsg)) == NULL) { 391155131Srwatson au_free_token(subject); 392155131Srwatson syslog(LOG_ERR, "%s: au_to_text() failed", func); 393155131Srwatson return (kAUMakeTextTokErr); 394155131Srwatson } 395155131Srwatson 396155131Srwatson return (audit_write(event_code, subject, errtok, -1, errcode)); 397155131Srwatson} 398155131Srwatson 399155131Srwatson/* 400155131Srwatson * Same caveats as audit_write(). In addition, this function explicitly 401155131Srwatson * assumes failure; use audit_write_success_self() otherwise. 402155131Srwatson * 403155131Srwatson * XXX This should let the caller pass an error return value rather than 404155131Srwatson * hard-coding -1. 405155131Srwatson */ 406155131Srwatsonint 407155131Srwatsonaudit_write_failure_self(short event_code, char *errmsg, int errret) 408155131Srwatson{ 409155131Srwatson char *func = "audit_write_failure_self()"; 410155131Srwatson token_t *subject, *errtok; 411155131Srwatson 412155131Srwatson if ((subject = au_to_me()) == NULL) { 413155131Srwatson syslog(LOG_ERR, "%s: au_to_me() failed", func); 414155131Srwatson return (kAUMakeSubjectTokErr); 415155131Srwatson } 416155131Srwatson /* tokenize and save the error message */ 417155131Srwatson if ((errtok = au_to_text(errmsg)) == NULL) { 418155131Srwatson au_free_token(subject); 419155131Srwatson syslog(LOG_ERR, "%s: au_to_text() failed", func); 420155131Srwatson return (kAUMakeTextTokErr); 421155131Srwatson } 422155131Srwatson return (audit_write(event_code, subject, errtok, -1, errret)); 423155131Srwatson} 424155131Srwatson 425155131Srwatson/* 426155131Srwatson * For auditing errors during login. Such errors are implicitly 427155131Srwatson * non-attributable (i.e., not ascribable to any user). 428155131Srwatson * 429155131Srwatson * Assumes, like all wrapper calls, that the caller has previously checked 430155131Srwatson * that auditing is enabled via the audit_get_state() call. 431155131Srwatson */ 432155131Srwatsonint 433155131Srwatsonaudit_write_failure_na(short event_code, char *errmsg, int errret, uid_t euid, 434155131Srwatson uid_t egid, pid_t pid, au_tid_t *tid) 435155131Srwatson{ 436155131Srwatson 437155131Srwatson return (audit_write_failure(event_code, errmsg, errret, -1, euid, 438155131Srwatson egid, -1, -1, pid, -1, tid)); 439155131Srwatson} 440155131Srwatson 441155131Srwatson/* END OF au_write() WRAPPERS */ 442155131Srwatson 443155131Srwatson#ifdef __APPLE__ 444155131Srwatsonvoid 445155131Srwatsonaudit_token_to_au32(audit_token_t atoken, uid_t *auidp, uid_t *euidp, 446155131Srwatson gid_t *egidp, uid_t *ruidp, gid_t *rgidp, pid_t *pidp, au_asid_t *asidp, 447155131Srwatson au_tid_t *tidp) 448155131Srwatson{ 449155131Srwatson 450155131Srwatson if (auidp != NULL) 451155131Srwatson *auidp = (uid_t)atoken.val[0]; 452155131Srwatson if (euidp != NULL) 453155131Srwatson *euidp = (uid_t)atoken.val[1]; 454155131Srwatson if (egidp != NULL) 455155131Srwatson *egidp = (gid_t)atoken.val[2]; 456155131Srwatson if (ruidp != NULL) 457155131Srwatson *ruidp = (uid_t)atoken.val[3]; 458155131Srwatson if (rgidp != NULL) 459155131Srwatson *rgidp = (gid_t)atoken.val[4]; 460155131Srwatson if (pidp != NULL) 461155131Srwatson *pidp = (pid_t)atoken.val[5]; 462155131Srwatson if (asidp != NULL) 463155131Srwatson *asidp = (au_asid_t)atoken.val[6]; 464155131Srwatson if (tidp != NULL) { 465155131Srwatson audit_set_terminal_host(&tidp->machine); 466155131Srwatson tidp->port = (dev_t)atoken.val[7]; 467155131Srwatson } 468155131Srwatson} 469155131Srwatson#endif /* !__APPLE__ */ 470