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