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