bsm_wrappers.c revision 155518
1/* 2 * Copyright (c) 2004 Apple Computer, Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 14 * its contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR 21 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 25 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 26 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * POSSIBILITY OF SUCH DAMAGE. 28 * 29 * $P4: //depot/projects/trustedbsd/openbsm/libbsm/bsm_wrappers.c#16 $ 30 */ 31 32#ifdef __APPLE__ 33#define _SYS_AUDIT_H /* Prevent include of sys/audit.h. */ 34#endif 35 36#include <sys/param.h> 37#include <sys/stat.h> 38#include <sys/sysctl.h> 39 40#include <bsm/libbsm.h> 41 42#include <unistd.h> 43#include <syslog.h> 44#include <string.h> 45#include <errno.h> 46 47/* These are not advertised in libbsm.h */ 48int audit_set_terminal_port(dev_t *p); 49int audit_set_terminal_host(uint32_t *m); 50 51int 52audit_set_terminal_port(dev_t *p) 53{ 54 struct stat st; 55 56 if (p == NULL) 57 return (kAUBadParamErr); 58 59 *p = NODEV; 60 61 /* for /usr/bin/login, try fstat() first */ 62 if (fstat(STDIN_FILENO, &st) != 0) { 63 if (errno != EBADF) { 64 syslog(LOG_ERR, "fstat() failed (%s)", 65 strerror(errno)); 66 return (kAUStatErr); 67 } 68 if (stat("/dev/console", &st) != 0) { 69 syslog(LOG_ERR, "stat() failed (%s)", 70 strerror(errno)); 71 return (kAUStatErr); 72 } 73 } 74 *p = st.st_rdev; 75 return (kAUNoErr); 76} 77 78int 79audit_set_terminal_host(uint32_t *m) 80{ 81 int name[2] = { CTL_KERN, KERN_HOSTID }; 82 size_t len; 83 84 if (m == NULL) 85 return (kAUBadParamErr); 86 *m = 0; 87 len = sizeof(*m); 88 if (sysctl(name, 2, m, &len, NULL, 0) != 0) { 89 syslog(LOG_ERR, "sysctl() failed (%s)", strerror(errno)); 90 return (kAUSysctlErr); 91 } 92 return (kAUNoErr); 93} 94 95int 96audit_set_terminal_id(au_tid_t *tid) 97{ 98 int ret; 99 100 if (tid == NULL) 101 return (kAUBadParamErr); 102 if ((ret = audit_set_terminal_port(&tid->port)) != kAUNoErr) 103 return (ret); 104 return (audit_set_terminal_host(&tid->machine)); 105} 106 107/* 108 * This is OK for those callers who have only one token to write. If you have 109 * multiple tokens that logically form part of the same audit record, you need 110 * to use the existing au_open()/au_write()/au_close() API: 111 * 112 * aufd = au_open(); 113 * tok = au_to_random_token_1(...); 114 * au_write(aufd, tok); 115 * tok = au_to_random_token_2(...); 116 * au_write(aufd, tok); 117 * ... 118 * au_close(aufd, 1, AUE_your_event_type); 119 * 120 * Assumes, like all wrapper calls, that the caller has previously checked 121 * that auditing is enabled via the audit_get_state() call. 122 * 123 * XXX: Should be more robust against bad arguments. 124 */ 125int 126audit_write(short event_code, token_t *subject, token_t *misctok, char retval, 127 int errcode) 128{ 129 int aufd; 130 char *func = "audit_write()"; 131 token_t *rettok; 132 133 if ((aufd = au_open()) == -1) { 134 au_free_token(subject); 135 au_free_token(misctok); 136 syslog(LOG_ERR, "%s: au_open() failed", func); 137 return (kAUOpenErr); 138 } 139 140 /* Save subject. */ 141 if (subject && au_write(aufd, subject) == -1) { 142 au_free_token(subject); 143 au_free_token(misctok); 144 (void)au_close(aufd, 0, event_code); 145 syslog(LOG_ERR, "%s: write of subject failed", func); 146 return (kAUWriteSubjectTokErr); 147 } 148 149 /* Save the event-specific token. */ 150 if (misctok && au_write(aufd, misctok) == -1) { 151 au_free_token(misctok); 152 (void)au_close(aufd, 0, event_code); 153 syslog(LOG_ERR, "%s: write of caller token failed", func); 154 return (kAUWriteCallerTokErr); 155 } 156 157 /* Tokenize and save the return value. */ 158 if ((rettok = au_to_return32(retval, errcode)) == NULL) { 159 (void)au_close(aufd, 0, event_code); 160 syslog(LOG_ERR, "%s: au_to_return32() failed", func); 161 return (kAUMakeReturnTokErr); 162 } 163 164 if (au_write(aufd, rettok) == -1) { 165 au_free_token(rettok); 166 (void)au_close(aufd, 0, event_code); 167 syslog(LOG_ERR, "%s: write of return code failed", func); 168 return (kAUWriteReturnTokErr); 169 } 170 171 /* 172 * au_close()'s second argument is "keep": if keep == 0, the record is 173 * discarded. We assume the caller wouldn't have bothered with this 174 * function if it hadn't already decided to keep the record. 175 */ 176 if (au_close(aufd, 1, event_code) < 0) { 177 syslog(LOG_ERR, "%s: au_close() failed", func); 178 return (kAUCloseErr); 179 } 180 181 return (kAUNoErr); 182} 183 184/* 185 * Same caveats as audit_write(). In addition, this function explicitly 186 * assumes success; use audit_write_failure() on error. 187 */ 188int 189audit_write_success(short event_code, token_t *tok, au_id_t auid, uid_t euid, 190 gid_t egid, uid_t ruid, gid_t rgid, pid_t pid, au_asid_t sid, 191 au_tid_t *tid) 192{ 193 char *func = "audit_write_success()"; 194 token_t *subject = NULL; 195 196 /* Tokenize and save subject. */ 197 subject = au_to_subject32(auid, euid, egid, ruid, rgid, pid, sid, 198 tid); 199 if (subject == NULL) { 200 syslog(LOG_ERR, "%s: au_to_subject32() failed", func); 201 return kAUMakeSubjectTokErr; 202 } 203 204 return (audit_write(event_code, subject, tok, 0, 0)); 205} 206 207/* 208 * Same caveats as audit_write(). In addition, this function explicitly 209 * assumes success; use audit_write_failure_self() on error. 210 */ 211int 212audit_write_success_self(short event_code, token_t *tok) 213{ 214 token_t *subject; 215 char *func = "audit_write_success_self()"; 216 217 if ((subject = au_to_me()) == NULL) { 218 syslog(LOG_ERR, "%s: au_to_me() failed", func); 219 return (kAUMakeSubjectTokErr); 220 } 221 222 return (audit_write(event_code, subject, tok, 0, 0)); 223} 224 225/* 226 * Same caveats as audit_write(). In addition, this function explicitly 227 * assumes failure; use audit_write_success() otherwise. 228 * 229 * XXX This should let the caller pass an error return value rather than 230 * hard-coding -1. 231 */ 232int 233audit_write_failure(short event_code, char *errmsg, int errcode, au_id_t auid, 234 uid_t euid, gid_t egid, uid_t ruid, gid_t rgid, pid_t pid, au_asid_t sid, 235 au_tid_t *tid) 236{ 237 char *func = "audit_write_failure()"; 238 token_t *subject, *errtok; 239 240 subject = au_to_subject32(auid, euid, egid, ruid, rgid, pid, sid, tid); 241 if (subject == NULL) { 242 syslog(LOG_ERR, "%s: au_to_subject32() failed", func); 243 return (kAUMakeSubjectTokErr); 244 } 245 246 /* tokenize and save the error message */ 247 if ((errtok = au_to_text(errmsg)) == NULL) { 248 au_free_token(subject); 249 syslog(LOG_ERR, "%s: au_to_text() failed", func); 250 return (kAUMakeTextTokErr); 251 } 252 253 return (audit_write(event_code, subject, errtok, -1, errcode)); 254} 255 256/* 257 * Same caveats as audit_write(). In addition, this function explicitly 258 * assumes failure; use audit_write_success_self() otherwise. 259 * 260 * XXX This should let the caller pass an error return value rather than 261 * hard-coding -1. 262 */ 263int 264audit_write_failure_self(short event_code, char *errmsg, int errret) 265{ 266 char *func = "audit_write_failure_self()"; 267 token_t *subject, *errtok; 268 269 if ((subject = au_to_me()) == NULL) { 270 syslog(LOG_ERR, "%s: au_to_me() failed", func); 271 return (kAUMakeSubjectTokErr); 272 } 273 /* tokenize and save the error message */ 274 if ((errtok = au_to_text(errmsg)) == NULL) { 275 au_free_token(subject); 276 syslog(LOG_ERR, "%s: au_to_text() failed", func); 277 return (kAUMakeTextTokErr); 278 } 279 return (audit_write(event_code, subject, errtok, -1, errret)); 280} 281 282/* 283 * For auditing errors during login. Such errors are implicitly 284 * non-attributable (i.e., not ascribable to any user). 285 * 286 * Assumes, like all wrapper calls, that the caller has previously checked 287 * that auditing is enabled via the audit_get_state() call. 288 */ 289int 290audit_write_failure_na(short event_code, char *errmsg, int errret, uid_t euid, 291 uid_t egid, pid_t pid, au_tid_t *tid) 292{ 293 294 return (audit_write_failure(event_code, errmsg, errret, -1, euid, 295 egid, -1, -1, pid, -1, tid)); 296} 297 298/* END OF au_write() WRAPPERS */ 299 300#ifdef __APPLE__ 301void 302audit_token_to_au32(audit_token_t atoken, uid_t *auidp, uid_t *euidp, 303 gid_t *egidp, uid_t *ruidp, gid_t *rgidp, pid_t *pidp, au_asid_t *asidp, 304 au_tid_t *tidp) 305{ 306 307 if (auidp != NULL) 308 *auidp = (uid_t)atoken.val[0]; 309 if (euidp != NULL) 310 *euidp = (uid_t)atoken.val[1]; 311 if (egidp != NULL) 312 *egidp = (gid_t)atoken.val[2]; 313 if (ruidp != NULL) 314 *ruidp = (uid_t)atoken.val[3]; 315 if (rgidp != NULL) 316 *rgidp = (gid_t)atoken.val[4]; 317 if (pidp != NULL) 318 *pidp = (pid_t)atoken.val[5]; 319 if (asidp != NULL) 320 *asidp = (au_asid_t)atoken.val[6]; 321 if (tidp != NULL) { 322 audit_set_terminal_host(&tidp->machine); 323 tidp->port = (dev_t)atoken.val[7]; 324 } 325} 326#endif /* !__APPLE__ */ 327