1 /*- 2 * Copyright (c) 2004 Apple 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 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#28 $ 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 39 #ifdef __APPLE__ 40 #include <sys/queue.h> /* Our bsm/audit.h doesn't include queue.h. */ 41 #endif 42 43 #include <sys/sysctl.h> 44 45 #include <bsm/libbsm.h> 46 47 #include <unistd.h> 48 #include <syslog.h> 49 #include <stdarg.h> 50 #include <string.h> 51 #include <errno.h> 52 53 /* These are not advertised in libbsm.h */ 54 int audit_set_terminal_port(dev_t *p); 55 int audit_set_terminal_host(uint32_t *m); 56 57 /* 58 * General purpose audit submission mechanism for userspace. 59 */ 60 int 61 audit_submit(short au_event, au_id_t auid, char status, 62 int reterr, const char *fmt, ...) 63 { 64 char text[MAX_AUDITSTRING_LEN]; 65 token_t *token; 66 long acond; 67 va_list ap; 68 pid_t pid; 69 int error, afd, subj_ex; 70 struct auditinfo ai; 71 struct auditinfo_addr aia; 72 au_tid_t atid; 73 74 if (auditon(A_GETCOND, &acond, sizeof(acond)) < 0) { 75 /* 76 * If auditon(2) returns ENOSYS, then audit has not been 77 * compiled into the kernel, so just return. 78 */ 79 if (errno == ENOSYS) 80 return (0); 81 error = errno; 82 syslog(LOG_AUTH | LOG_ERR, "audit: auditon failed: %s", 83 strerror(errno)); 84 errno = error; 85 return (-1); 86 } 87 if (acond == AUC_NOAUDIT) 88 return (0); 89 afd = au_open(); 90 if (afd < 0) { 91 error = errno; 92 syslog(LOG_AUTH | LOG_ERR, "audit: au_open failed: %s", 93 strerror(errno)); 94 errno = error; 95 return (-1); 96 } 97 /* 98 * Try to use getaudit_addr(2) first. If this kernel does not support 99 * it, then fall back on to getaudit(2). 100 */ 101 subj_ex = 0; 102 error = getaudit_addr(&aia, sizeof(aia)); 103 if (error < 0 && errno == ENOSYS) { 104 error = getaudit(&ai); 105 if (error < 0) { 106 error = errno; 107 syslog(LOG_AUTH | LOG_ERR, "audit: getaudit failed: %s", 108 strerror(errno)); 109 errno = error; 110 return (-1); 111 } 112 /* 113 * Convert this auditinfo_t to an auditinfo_addr_t to make the 114 * following code less complicated wrt to preselection and 115 * subject token generation. 116 */ 117 aia.ai_auid = ai.ai_auid; 118 aia.ai_mask = ai.ai_mask; 119 aia.ai_asid = ai.ai_asid; 120 aia.ai_termid.at_type = AU_IPv4; 121 aia.ai_termid.at_addr[0] = ai.ai_termid.machine; 122 aia.ai_termid.at_port = ai.ai_termid.port; 123 } else if (error < 0) { 124 error = errno; 125 syslog(LOG_AUTH | LOG_ERR, "audit: getaudit_addr failed: %s", 126 strerror(errno)); 127 errno = error; 128 return (-1); 129 } 130 /* 131 * NB: We should be performing pre-selection here now that we have the 132 * masks for this process. 133 */ 134 if (aia.ai_termid.at_type == AU_IPv6) 135 subj_ex = 1; 136 pid = getpid(); 137 if (subj_ex == 0) { 138 atid.port = aia.ai_termid.at_port; 139 atid.machine = aia.ai_termid.at_addr[0]; 140 token = au_to_subject32(auid, geteuid(), getegid(), 141 getuid(), getgid(), pid, pid, &atid); 142 } else 143 token = au_to_subject_ex(auid, geteuid(), getegid(), 144 getuid(), getgid(), pid, pid, &aia.ai_termid); 145 if (token == NULL) { 146 syslog(LOG_AUTH | LOG_ERR, 147 "audit: unable to build subject token"); 148 (void) au_close(afd, AU_TO_NO_WRITE, au_event); 149 errno = EPERM; 150 return (-1); 151 } 152 if (au_write(afd, token) < 0) { 153 error = errno; 154 syslog(LOG_AUTH | LOG_ERR, 155 "audit: au_write failed: %s", strerror(errno)); 156 (void) au_close(afd, AU_TO_NO_WRITE, au_event); 157 errno = error; 158 return (-1); 159 } 160 if (fmt != NULL) { 161 va_start(ap, fmt); 162 (void) vsnprintf(text, MAX_AUDITSTRING_LEN, fmt, ap); 163 va_end(ap); 164 token = au_to_text(text); 165 if (token == NULL) { 166 syslog(LOG_AUTH | LOG_ERR, 167 "audit: failed to generate text token"); 168 (void) au_close(afd, AU_TO_NO_WRITE, au_event); 169 errno = EPERM; 170 return (-1); 171 } 172 if (au_write(afd, token) < 0) { 173 error = errno; 174 syslog(LOG_AUTH | LOG_ERR, 175 "audit: au_write failed: %s", strerror(errno)); 176 (void) au_close(afd, AU_TO_NO_WRITE, au_event); 177 errno = error; 178 return (-1); 179 } 180 } 181 token = au_to_return32(status, au_errno_to_bsm(reterr)); 182 if (token == NULL) { 183 syslog(LOG_AUTH | LOG_ERR, 184 "audit: enable to build return token"); 185 (void) au_close(afd, AU_TO_NO_WRITE, au_event); 186 errno = EPERM; 187 return (-1); 188 } 189 if (au_write(afd, token) < 0) { 190 error = errno; 191 syslog(LOG_AUTH | LOG_ERR, 192 "audit: au_write failed: %s", strerror(errno)); 193 (void) au_close(afd, AU_TO_NO_WRITE, au_event); 194 errno = error; 195 return (-1); 196 } 197 if (au_close(afd, AU_TO_WRITE, au_event) < 0) { 198 error = errno; 199 syslog(LOG_AUTH | LOG_ERR, "audit: record not committed"); 200 errno = error; 201 return (-1); 202 } 203 return (0); 204 } 205 206 int 207 audit_set_terminal_port(dev_t *p) 208 { 209 struct stat st; 210 211 if (p == NULL) 212 return (kAUBadParamErr); 213 214 #ifdef NODEV 215 *p = NODEV; 216 #else 217 *p = -1; 218 #endif 219 220 /* for /usr/bin/login, try fstat() first */ 221 if (fstat(STDIN_FILENO, &st) != 0) { 222 if (errno != EBADF) { 223 syslog(LOG_ERR, "fstat() failed (%s)", 224 strerror(errno)); 225 return (kAUStatErr); 226 } 227 if (stat("/dev/console", &st) != 0) { 228 syslog(LOG_ERR, "stat() failed (%s)", 229 strerror(errno)); 230 return (kAUStatErr); 231 } 232 } 233 *p = st.st_rdev; 234 return (kAUNoErr); 235 } 236 237 int 238 audit_set_terminal_host(uint32_t *m) 239 { 240 241 #ifdef KERN_HOSTID 242 int name[2] = { CTL_KERN, KERN_HOSTID }; 243 size_t len; 244 245 if (m == NULL) 246 return (kAUBadParamErr); 247 *m = 0; 248 len = sizeof(*m); 249 if (sysctl(name, 2, m, &len, NULL, 0) != 0) { 250 syslog(LOG_ERR, "sysctl() failed (%s)", strerror(errno)); 251 return (kAUSysctlErr); 252 } 253 return (kAUNoErr); 254 #else 255 *m = -1; 256 return (kAUNoErr); 257 #endif 258 } 259 260 int 261 audit_set_terminal_id(au_tid_t *tid) 262 { 263 int ret; 264 265 if (tid == NULL) 266 return (kAUBadParamErr); 267 if ((ret = audit_set_terminal_port(&tid->port)) != kAUNoErr) 268 return (ret); 269 return (audit_set_terminal_host(&tid->machine)); 270 } 271 272 /* 273 * This is OK for those callers who have only one token to write. If you have 274 * multiple tokens that logically form part of the same audit record, you need 275 * to use the existing au_open()/au_write()/au_close() API: 276 * 277 * aufd = au_open(); 278 * tok = au_to_random_token_1(...); 279 * au_write(aufd, tok); 280 * tok = au_to_random_token_2(...); 281 * au_write(aufd, tok); 282 * ... 283 * au_close(aufd, AU_TO_WRITE, AUE_your_event_type); 284 * 285 * Assumes, like all wrapper calls, that the caller has previously checked 286 * that auditing is enabled via the audit_get_state() call. 287 * 288 * XXX: Should be more robust against bad arguments. 289 */ 290 int 291 audit_write(short event_code, token_t *subject, token_t *misctok, char retval, 292 int errcode) 293 { 294 int aufd; 295 char *func = "audit_write()"; 296 token_t *rettok; 297 298 if ((aufd = au_open()) == -1) { 299 au_free_token(subject); 300 au_free_token(misctok); 301 syslog(LOG_ERR, "%s: au_open() failed", func); 302 return (kAUOpenErr); 303 } 304 305 /* Save subject. */ 306 if (subject && au_write(aufd, subject) == -1) { 307 au_free_token(subject); 308 au_free_token(misctok); 309 (void)au_close(aufd, AU_TO_NO_WRITE, event_code); 310 syslog(LOG_ERR, "%s: write of subject failed", func); 311 return (kAUWriteSubjectTokErr); 312 } 313 314 /* Save the event-specific token. */ 315 if (misctok && au_write(aufd, misctok) == -1) { 316 au_free_token(misctok); 317 (void)au_close(aufd, AU_TO_NO_WRITE, event_code); 318 syslog(LOG_ERR, "%s: write of caller token failed", func); 319 return (kAUWriteCallerTokErr); 320 } 321 322 /* Tokenize and save the return value. */ 323 if ((rettok = au_to_return32(retval, errcode)) == NULL) { 324 (void)au_close(aufd, AU_TO_NO_WRITE, event_code); 325 syslog(LOG_ERR, "%s: au_to_return32() failed", func); 326 return (kAUMakeReturnTokErr); 327 } 328 329 if (au_write(aufd, rettok) == -1) { 330 au_free_token(rettok); 331 (void)au_close(aufd, AU_TO_NO_WRITE, event_code); 332 syslog(LOG_ERR, "%s: write of return code failed", func); 333 return (kAUWriteReturnTokErr); 334 } 335 336 /* 337 * We assume the caller wouldn't have bothered with this 338 * function if it hadn't already decided to keep the record. 339 */ 340 if (au_close(aufd, AU_TO_WRITE, event_code) < 0) { 341 syslog(LOG_ERR, "%s: au_close() failed", func); 342 return (kAUCloseErr); 343 } 344 345 return (kAUNoErr); 346 } 347 348 /* 349 * Same caveats as audit_write(). In addition, this function explicitly 350 * assumes success; use audit_write_failure() on error. 351 */ 352 int 353 audit_write_success(short event_code, token_t *tok, au_id_t auid, uid_t euid, 354 gid_t egid, uid_t ruid, gid_t rgid, pid_t pid, au_asid_t sid, 355 au_tid_t *tid) 356 { 357 char *func = "audit_write_success()"; 358 token_t *subject = NULL; 359 360 /* Tokenize and save subject. */ 361 subject = au_to_subject32(auid, euid, egid, ruid, rgid, pid, sid, 362 tid); 363 if (subject == NULL) { 364 syslog(LOG_ERR, "%s: au_to_subject32() failed", func); 365 return kAUMakeSubjectTokErr; 366 } 367 368 return (audit_write(event_code, subject, tok, 0, 0)); 369 } 370 371 /* 372 * Same caveats as audit_write(). In addition, this function explicitly 373 * assumes success; use audit_write_failure_self() on error. 374 */ 375 int 376 audit_write_success_self(short event_code, token_t *tok) 377 { 378 token_t *subject; 379 char *func = "audit_write_success_self()"; 380 381 if ((subject = au_to_me()) == NULL) { 382 syslog(LOG_ERR, "%s: au_to_me() failed", func); 383 return (kAUMakeSubjectTokErr); 384 } 385 386 return (audit_write(event_code, subject, tok, 0, 0)); 387 } 388 389 /* 390 * Same caveats as audit_write(). In addition, this function explicitly 391 * assumes failure; use audit_write_success() otherwise. 392 * 393 * XXX This should let the caller pass an error return value rather than 394 * hard-coding -1. 395 */ 396 int 397 audit_write_failure(short event_code, char *errmsg, int errcode, au_id_t auid, 398 uid_t euid, gid_t egid, uid_t ruid, gid_t rgid, pid_t pid, au_asid_t sid, 399 au_tid_t *tid) 400 { 401 char *func = "audit_write_failure()"; 402 token_t *subject, *errtok; 403 404 subject = au_to_subject32(auid, euid, egid, ruid, rgid, pid, sid, tid); 405 if (subject == NULL) { 406 syslog(LOG_ERR, "%s: au_to_subject32() failed", func); 407 return (kAUMakeSubjectTokErr); 408 } 409 410 /* tokenize and save the error message */ 411 if ((errtok = au_to_text(errmsg)) == NULL) { 412 au_free_token(subject); 413 syslog(LOG_ERR, "%s: au_to_text() failed", func); 414 return (kAUMakeTextTokErr); 415 } 416 417 return (audit_write(event_code, subject, errtok, -1, errcode)); 418 } 419 420 /* 421 * Same caveats as audit_write(). In addition, this function explicitly 422 * assumes failure; use audit_write_success_self() otherwise. 423 * 424 * XXX This should let the caller pass an error return value rather than 425 * hard-coding -1. 426 */ 427 int 428 audit_write_failure_self(short event_code, char *errmsg, int errret) 429 { 430 char *func = "audit_write_failure_self()"; 431 token_t *subject, *errtok; 432 433 if ((subject = au_to_me()) == NULL) { 434 syslog(LOG_ERR, "%s: au_to_me() failed", func); 435 return (kAUMakeSubjectTokErr); 436 } 437 /* tokenize and save the error message */ 438 if ((errtok = au_to_text(errmsg)) == NULL) { 439 au_free_token(subject); 440 syslog(LOG_ERR, "%s: au_to_text() failed", func); 441 return (kAUMakeTextTokErr); 442 } 443 return (audit_write(event_code, subject, errtok, -1, errret)); 444 } 445 446 /* 447 * For auditing errors during login. Such errors are implicitly 448 * non-attributable (i.e., not ascribable to any user). 449 * 450 * Assumes, like all wrapper calls, that the caller has previously checked 451 * that auditing is enabled via the audit_get_state() call. 452 */ 453 int 454 audit_write_failure_na(short event_code, char *errmsg, int errret, uid_t euid, 455 uid_t egid, pid_t pid, au_tid_t *tid) 456 { 457 458 return (audit_write_failure(event_code, errmsg, errret, -1, euid, 459 egid, -1, -1, pid, -1, tid)); 460 } 461 462 /* END OF au_write() WRAPPERS */ 463 464 #ifdef __APPLE__ 465 void 466 audit_token_to_au32(audit_token_t atoken, uid_t *auidp, uid_t *euidp, 467 gid_t *egidp, uid_t *ruidp, gid_t *rgidp, pid_t *pidp, au_asid_t *asidp, 468 au_tid_t *tidp) 469 { 470 471 if (auidp != NULL) 472 *auidp = (uid_t)atoken.val[0]; 473 if (euidp != NULL) 474 *euidp = (uid_t)atoken.val[1]; 475 if (egidp != NULL) 476 *egidp = (gid_t)atoken.val[2]; 477 if (ruidp != NULL) 478 *ruidp = (uid_t)atoken.val[3]; 479 if (rgidp != NULL) 480 *rgidp = (gid_t)atoken.val[4]; 481 if (pidp != NULL) 482 *pidp = (pid_t)atoken.val[5]; 483 if (asidp != NULL) 484 *asidp = (au_asid_t)atoken.val[6]; 485 if (tidp != NULL) { 486 audit_set_terminal_host(&tidp->machine); 487 tidp->port = (dev_t)atoken.val[7]; 488 } 489 } 490 #endif /* !__APPLE__ */ 491