auditd_lib.c revision 187214
1/*- 2 * Copyright (c) 2008 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/libauditd/auditd_lib.c#2 $ 30 */ 31 32#include <sys/param.h> 33 34#include <config/config.h> 35 36#include <sys/dirent.h> 37#include <sys/mount.h> 38#include <sys/socket.h> 39#ifdef HAVE_FULL_QUEUE_H 40#include <sys/queue.h> 41#else /* !HAVE_FULL_QUEUE_H */ 42#include <compat/queue.h> 43#endif /* !HAVE_FULL_QUEUE_H */ 44 45#include <sys/stat.h> 46#include <sys/time.h> 47 48#include <netinet/in.h> 49 50#include <bsm/audit.h> 51#include <bsm/audit_uevents.h> 52#include <bsm/auditd_lib.h> 53#include <bsm/libbsm.h> 54 55#include <err.h> 56#include <errno.h> 57#include <fcntl.h> 58#include <stdio.h> 59#include <string.h> 60#include <stdlib.h> 61#include <time.h> 62#include <unistd.h> 63#include <netdb.h> 64 65#ifdef __APPLE__ 66#include <notify.h> 67#ifndef __BSM_INTERNAL_NOTIFY_KEY 68#define __BSM_INTERNAL_NOTIFY_KEY "com.apple.audit.change" 69#endif /* __BSM_INTERNAL_NOTIFY_KEY */ 70#endif /* __APPLE__ */ 71 72/* 73 * XXX This is temporary until this is moved to <bsm/audit.h> and shared with 74 * the kernel. 75 */ 76#ifndef AUDIT_HARD_LIMIT_FREE_BLOCKS 77#define AUDIT_HARD_LIMIT_FREE_BLOCKS 4 78#endif 79 80struct dir_ent { 81 char *dirname; 82 uint8_t softlim; 83 uint8_t hardlim; 84 TAILQ_ENTRY(dir_ent) dirs; 85}; 86 87static TAILQ_HEAD(, dir_ent) dir_q; 88static int minval = -1; 89 90static char *auditd_errmsg[] = { 91 "no error", /* ADE_NOERR ( 0) */ 92 "could not parse audit_control(5) file", /* ADE_PARSE ( 1) */ 93 "auditon(2) failed", /* ADE_AUDITON ( 2) */ 94 "malloc(3) failed", /* ADE_NOMEM ( 3) */ 95 "all audit log directories over soft limit", /* ADE_SOFTLIM ( 4) */ 96 "all audit log directories over hard limit", /* ADE_HARDLIM ( 5) */ 97 "could not create file name string", /* ADE_STRERR ( 6) */ 98 "could not open audit record", /* ADE_AU_OPEN ( 7) */ 99 "could not close audit record", /* ADE_AU_CLOSE ( 8) */ 100 "could not set active audit session state", /* ADE_SETAUDIT ( 9) */ 101 "auditctl(2) failed (trail still swapped)", /* ADE_ACTL (10) */ 102 "auditctl(2) failed (trail not swapped)", /* ADE_ACTLERR (11) */ 103 "could not swap audit trail file", /* ADE_SWAPERR (12) */ 104 "could not rename crash recovery file", /* ADE_RENAME (13) */ 105 "could not read 'current' link file", /* ADE_READLINK (14) */ 106 "could not create 'current' link file", /* ADE_SYMLINK (15) */ 107 "invalid argument", /* ADE_INVAL (16) */ 108 "could not resolve hostname to address", /* ADE_GETADDR (17) */ 109 "address family not supported", /* ADE_ADDRFAM (18) */ 110}; 111 112#define MAXERRCODE (sizeof(auditd_errmsg) / sizeof(auditd_errmsg[0])) 113 114#define NA_EVENT_STR_SIZE 25 115#define POL_STR_SIZE 128 116 117 118/* 119 * Look up and return the error string for the given audit error code. 120 */ 121const char * 122auditd_strerror(int errcode) 123{ 124 int idx = -errcode; 125 126 if (idx < 0 || idx > (int)MAXERRCODE) 127 return ("Invalid auditd error code"); 128 129 return (auditd_errmsg[idx]); 130} 131 132 133/* 134 * Free our local list of directory names and init list 135 */ 136static void 137free_dir_q(void) 138{ 139 struct dir_ent *d1, *d2; 140 141 d1 = TAILQ_FIRST(&dir_q); 142 while (d1 != NULL) { 143 d2 = TAILQ_NEXT(d1, dirs); 144 free(d1->dirname); 145 free(d1); 146 d1 = d2; 147 } 148 TAILQ_INIT(&dir_q); 149} 150 151/* 152 * Concat the directory name to the given file name. 153 * XXX We should affix the hostname also 154 */ 155static char * 156affixdir(char *name, struct dir_ent *dirent) 157{ 158 char *fn = NULL; 159 160 /* 161 * Sanity check on file name. 162 */ 163 if (strlen(name) != (FILENAME_LEN - 1)) { 164 errno = EINVAL; 165 return (NULL); 166 } 167 168 asprintf(&fn, "%s/%s", dirent->dirname, name); 169 return (fn); 170} 171 172/* 173 * Insert the directory entry in the list by the way they are ordered in 174 * audit_control(5). Move the entries that are over the soft and hard limits 175 * toward the tail. 176 */ 177static void 178insert_orderly(struct dir_ent *denew) 179{ 180 struct dir_ent *dep; 181 182 TAILQ_FOREACH(dep, &dir_q, dirs) { 183 if (dep->softlim == 1 && denew->softlim == 0) { 184 TAILQ_INSERT_BEFORE(dep, denew, dirs); 185 return; 186 } 187 if (dep->hardlim == 1 && denew->hardlim == 0) { 188 TAILQ_INSERT_BEFORE(dep, denew, dirs); 189 return; 190 } 191 } 192 TAILQ_INSERT_TAIL(&dir_q, denew, dirs); 193} 194 195/* 196 * Get the host from audit_control(5) and set it in the audit kernel 197 * information. Return: 198 * ADE_NOERR on success. 199 * ADE_PARSE error parsing audit_control(5). 200 * ADE_AUDITON error getting/setting auditon(2) value. 201 * ADE_GETADDR error getting address info for host. 202 * ADE_ADDRFAM un-supported address family. 203 */ 204int 205auditd_set_host(void) 206{ 207 char hoststr[MAXHOSTNAMELEN]; 208 struct sockaddr_in6 *sin6; 209 struct sockaddr_in *sin; 210 struct addrinfo *res; 211 struct auditinfo_addr aia; 212 int error, ret = ADE_NOERR; 213 214 if (getachost(hoststr, MAXHOSTNAMELEN) != 0) { 215 216 ret = ADE_PARSE; 217 218 /* 219 * To maintain reverse compatability with older audit_control 220 * files, simply drop a warning if the host parameter has not 221 * been set. However, we will explicitly disable the 222 * generation of extended audit header by passing in a zeroed 223 * termid structure. 224 */ 225 bzero(&aia, sizeof(aia)); 226 aia.ai_termid.at_type = AU_IPv4; 227 error = auditon(A_SETKAUDIT, &aia, sizeof(aia)); 228 if (error < 0 && errno != ENOSYS) 229 ret = ADE_AUDITON; 230 return (ret); 231 } 232 error = getaddrinfo(hoststr, NULL, NULL, &res); 233 if (error) 234 return (ADE_GETADDR); 235 switch (res->ai_family) { 236 case PF_INET6: 237 sin6 = (struct sockaddr_in6 *) res->ai_addr; 238 bcopy(&sin6->sin6_addr.s6_addr, 239 &aia.ai_termid.at_addr[0], sizeof(struct in6_addr)); 240 aia.ai_termid.at_type = AU_IPv6; 241 break; 242 243 case PF_INET: 244 sin = (struct sockaddr_in *) res->ai_addr; 245 bcopy(&sin->sin_addr.s_addr, 246 &aia.ai_termid.at_addr[0], sizeof(struct in_addr)); 247 aia.ai_termid.at_type = AU_IPv4; 248 break; 249 250 default: 251 /* Un-supported address family in host parameter. */ 252 errno = EAFNOSUPPORT; 253 return (ADE_ADDRFAM); 254 } 255 256 if (auditon(A_SETKAUDIT, &aia, sizeof(aia)) < 0) 257 ret = ADE_AUDITON; 258 259 return (ret); 260} 261 262/* 263 * Get the min percentage of free blocks from audit_control(5) and that 264 * value in the kernel. Return: 265 * ADE_NOERR on success, 266 * ADE_PARSE error parsing audit_control(5), 267 * ADE_AUDITON error getting/setting auditon(2) value. 268 */ 269int 270auditd_set_minfree(void) 271{ 272 au_qctrl_t qctrl; 273 274 if (getacmin(&minval) != 0) 275 return (ADE_PARSE); 276 277 if (auditon(A_GETQCTRL, &qctrl, sizeof(qctrl)) != 0) 278 return (ADE_AUDITON); 279 280 if (qctrl.aq_minfree != minval) { 281 qctrl.aq_minfree = minval; 282 if (auditon(A_SETQCTRL, &qctrl, sizeof(qctrl)) != 0) 283 return (ADE_AUDITON); 284 } 285 286 return (0); 287} 288 289/* 290 * Parses the "dir" entry in audit_control(5) into an ordered list. Also, will 291 * set the minfree value if not already set. Arguments include function 292 * pointers to audit_warn functions for soft and hard limits. Returns: 293 * ADE_NOERR on success, 294 * ADE_PARSE error parsing audit_control(5), 295 * ADE_AUDITON error getting/setting auditon(2) value, 296 * ADE_NOMEM error allocating memory, 297 * ADE_SOFTLIM if all the directories are over the soft limit, 298 * ADE_HARDLIM if all the directories are over the hard limit, 299 */ 300int 301auditd_read_dirs(int (*warn_soft)(char *), int (*warn_hard)(char *)) 302{ 303 char cur_dir[MAXNAMLEN]; 304 struct dir_ent *dirent; 305 struct statfs sfs; 306 int err; 307 char soft, hard; 308 int tcnt = 0; 309 int scnt = 0; 310 int hcnt = 0; 311 312 if (minval == -1 && (err = auditd_set_minfree()) != 0) 313 return (err); 314 315 /* 316 * Init directory q. Force a re-read of the file the next time. 317 */ 318 free_dir_q(); 319 endac(); 320 321 /* 322 * Read the list of directories into an ordered linked list 323 * admin's preference, then those over soft limit and, finally, 324 * those over the hard limit. 325 * 326 * XXX We should use the reentrant interfaces once they are 327 * available. 328 */ 329 while (getacdir(cur_dir, MAXNAMLEN) >= 0) { 330 if (statfs(cur_dir, &sfs) < 0) 331 continue; /* XXX should warn */ 332 soft = (sfs.f_bfree < (sfs.f_blocks / (100 / minval))) ? 1 : 0; 333 hard = (sfs.f_bfree < AUDIT_HARD_LIMIT_FREE_BLOCKS) ? 1 : 0; 334 if (soft) { 335 if (warn_soft) 336 (*warn_soft)(cur_dir); 337 scnt++; 338 } 339 if (hard) { 340 if (warn_hard) 341 (*warn_hard)(cur_dir); 342 hcnt++; 343 } 344 dirent = (struct dir_ent *) malloc(sizeof(struct dir_ent)); 345 if (dirent == NULL) 346 return (ADE_NOMEM); 347 dirent->softlim = soft; 348 dirent->hardlim = hard; 349 dirent->dirname = (char *) malloc(MAXNAMLEN); 350 if (dirent->dirname == NULL) { 351 free(dirent); 352 return (ADE_NOMEM); 353 } 354 strlcpy(dirent->dirname, cur_dir, MAXNAMLEN); 355 insert_orderly(dirent); 356 tcnt++; 357 } 358 359 if (hcnt == tcnt) 360 return (ADE_HARDLIM); 361 if (scnt == tcnt) 362 return (ADE_SOFTLIM); 363 return (0); 364} 365 366void 367auditd_close_dirs(void) 368{ 369 free_dir_q(); 370 minval = -1; 371} 372 373 374/* 375 * Process the audit event file, obtaining a class mapping for each event, and 376 * set that mapping into the kernel. Return: 377 * n number of event mappings that were successfully processed, 378 * ADE_NOMEM if there was an error allocating memory. 379 */ 380int 381auditd_set_evcmap(void) 382{ 383 au_event_ent_t ev, *evp; 384 au_evclass_map_t evc_map; 385 int ctr = 0; 386 387 388 /* 389 * XXX There's a risk here that the BSM library will return NULL 390 * for an event when it can't properly map it to a class. In that 391 * case, we will not process any events beyond the one that failed, 392 * but should. We need a way to get a count of the events. 393 */ 394 ev.ae_name = (char *)malloc(AU_EVENT_NAME_MAX); 395 ev.ae_desc = (char *)malloc(AU_EVENT_DESC_MAX); 396 if ((ev.ae_name == NULL) || (ev.ae_desc == NULL)) { 397 if (ev.ae_name != NULL) 398 free(ev.ae_name); 399 return (ADE_NOMEM); 400 } 401 402 /* 403 * XXXRW: Currently we have no way to remove mappings from the kernel 404 * when they are removed from the file-based mappings. 405 */ 406 evp = &ev; 407 setauevent(); 408 while ((evp = getauevent_r(evp)) != NULL) { 409 evc_map.ec_number = evp->ae_number; 410 evc_map.ec_class = evp->ae_class; 411 if (auditon(A_SETCLASS, &evc_map, sizeof(au_evclass_map_t)) 412 == 0) 413 ctr++; 414 } 415 endauevent(); 416 free(ev.ae_name); 417 free(ev.ae_desc); 418 419 return (ctr); 420} 421 422/* 423 * Get the non-attributable event string and set the kernel mask. Return: 424 * ADE_NOERR on success, 425 * ADE_PARSE error parsing audit_control(5), 426 * ADE_AUDITON error setting the mask using auditon(2). 427 */ 428int 429auditd_set_namask(void) 430{ 431 au_mask_t aumask; 432 char naeventstr[NA_EVENT_STR_SIZE]; 433 434 if ((getacna(naeventstr, NA_EVENT_STR_SIZE) != 0) || 435 (getauditflagsbin(naeventstr, &aumask) != 0)) 436 return (ADE_PARSE); 437 438 if (auditon(A_SETKMASK, &aumask, sizeof(au_mask_t))) 439 return (ADE_AUDITON); 440 441 return (ADE_NOERR); 442} 443 444/* 445 * Set the audit control policy if a policy is configured in audit_control(5), 446 * implement the policy. However, if one isn't defined or if there is an error 447 * parsing the control file, set AUDIT_CNT to avoid leaving the system in a 448 * fragile state. Return: 449 * ADE_NOERR on success, 450 * ADE_PARSE error parsing audit_control(5), 451 * ADE_AUDITON error setting policy using auditon(2). 452 */ 453int 454auditd_set_policy(void) 455{ 456 long policy; 457 char polstr[POL_STR_SIZE]; 458 459 if ((getacpol(polstr, POL_STR_SIZE) != 0) || 460 (au_strtopol(polstr, &policy) != 0)) { 461 policy = AUDIT_CNT; 462 if (auditon(A_SETPOLICY, &policy, sizeof(policy))) 463 return (ADE_AUDITON); 464 return (ADE_PARSE); 465 } 466 467 if (auditon(A_SETPOLICY, &policy, sizeof(policy))) 468 return (ADE_AUDITON); 469 470 return (ADE_NOERR); 471} 472 473/* 474 * Set trail rotation size. Return: 475 * ADE_NOERR on success, 476 * ADE_PARSE error parsing audit_control(5), 477 * ADE_AUDITON error setting file size using auditon(2). 478 */ 479int 480auditd_set_fsize(void) 481{ 482 size_t filesz; 483 au_fstat_t au_fstat; 484 485 /* 486 * Set trail rotation size. 487 */ 488 if (getacfilesz(&filesz) != 0) 489 return (ADE_PARSE); 490 491 bzero(&au_fstat, sizeof(au_fstat)); 492 au_fstat.af_filesz = filesz; 493 if (auditon(A_SETFSIZE, &au_fstat, sizeof(au_fstat)) < 0) 494 return (ADE_AUDITON); 495 496 return (ADE_NOERR); 497} 498 499/* 500 * Create the new audit file with appropriate permissions and ownership. Try 501 * to clean up if something goes wrong. 502 */ 503static int 504open_trail(char *fname, gid_t gid) 505{ 506 int error, fd; 507 508 fd = open(fname, O_RDONLY | O_CREAT, S_IRUSR | S_IRGRP); 509 if (fd < 0) 510 return (-1); 511 if (fchown(fd, -1, gid) < 0) { 512 error = errno; 513 close(fd); 514 (void)unlink(fname); 515 errno = error; 516 return (-1); 517 } 518 return (fd); 519} 520 521/* 522 * Create the new audit trail file, swap with existing audit file. Arguments 523 * include timestamp for the filename, a pointer to a string for returning the 524 * new file name, GID for trail file, and audit_warn function pointer for 525 * 'getacdir()' errors. Returns: 526 * ADE_NOERR on success, 527 * ADE_STRERR if the file name string could not be created, 528 * ADE_SWAPERR if the audit trail file could not be swapped, 529 * ADE_ACTL if the auditctl(2) call failed but file swap still 530 * successful. 531 * ADE_ACTLERR if the auditctl(2) call failed and file swap failed. 532 * ADE_SYMLINK if symlink(2) failed updating the current link. 533 */ 534int 535auditd_swap_trail(char *TS, char **newfile, gid_t gid, 536 int (*warn_getacdir)(char *)) 537{ 538 char timestr[FILENAME_LEN]; 539 char *fn; 540 struct dir_ent *dirent; 541 int fd; 542 int error; 543 int saverrno = 0; 544 545 if (strlen(TS) != (TIMESTAMP_LEN - 1) || 546 snprintf(timestr, FILENAME_LEN, "%s.%s", TS, NOT_TERMINATED) < 0) { 547 errno = EINVAL; 548 return (ADE_STRERR); 549 } 550 551 /* Try until we succeed. */ 552 while ((dirent = TAILQ_FIRST(&dir_q))) { 553 if (dirent->hardlim) 554 continue; 555 if ((fn = affixdir(timestr, dirent)) == NULL) 556 return (ADE_STRERR); 557 558 /* 559 * Create and open the file; then close and pass to the 560 * kernel if all went well. 561 */ 562 fd = open_trail(fn, gid); 563 if (fd >= 0) { 564 error = auditctl(fn); 565 if (error) { 566 /* 567 * auditctl failed setting log file. 568 * Try again. 569 */ 570 saverrno = errno; 571 close(fd); 572 } else { 573 /* Success. */ 574 *newfile = fn; 575 close(fd); 576 if (error) 577 return (error); 578 if (saverrno) { 579 /* 580 * auditctl() failed but still 581 * successful. Return errno and "soft" 582 * error. 583 */ 584 errno = saverrno; 585 return (ADE_ACTL); 586 } 587 return (ADE_NOERR); 588 } 589 } 590 591 /* 592 * Tell the administrator about lack of permissions for dir. 593 */ 594 if (warn_getacdir != NULL) 595 (*warn_getacdir)(dirent->dirname); 596 } 597 if (saverrno) { 598 errno = saverrno; 599 return (ADE_ACTLERR); 600 } else 601 return (ADE_SWAPERR); 602} 603 604/* 605 * Mask calling process from being audited. Returns: 606 * ADE_NOERR on success, 607 * ADE_SETAUDIT if setaudit(2) fails. 608 */ 609int 610auditd_prevent_audit(void) 611{ 612 auditinfo_t ai; 613 614 /* 615 * To prevent event feedback cycles and avoid audit becoming stalled if 616 * auditing is suspended we mask this processes events from being 617 * audited. We allow the uid, tid, and mask fields to be implicitly 618 * set to zero, but do set the audit session ID to the PID. 619 * 620 * XXXRW: Is there more to it than this? 621 */ 622 bzero(&ai, sizeof(ai)); 623 ai.ai_asid = getpid(); 624 if (setaudit(&ai) != 0) 625 return (ADE_SETAUDIT); 626 return (ADE_NOERR); 627} 628 629/* 630 * Generate and submit audit record for audit startup or shutdown. The event 631 * argument can be AUE_audit_recovery, AUE_audit_startup or 632 * AUE_audit_shutdown. The path argument will add a path token, if not NULL. 633 * Returns: 634 * AUE_NOERR on success, 635 * ADE_NOMEM if memory allocation fails, 636 * ADE_AU_OPEN if au_open(3) fails, 637 * ADE_AU_CLOSE if au_close(3) fails. 638 */ 639int 640auditd_gen_record(int event, char *path) 641{ 642 int aufd; 643 uid_t uid; 644 pid_t pid; 645 char *autext = NULL; 646 token_t *tok; 647 struct auditinfo_addr aia; 648 649 if (event == AUE_audit_startup) 650 asprintf(&autext, "%s::Audit startup", getprogname()); 651 else if (event == AUE_audit_shutdown) 652 asprintf(&autext, "%s::Audit shutdown", getprogname()); 653 else if (event == AUE_audit_recovery) 654 asprintf(&autext, "%s::Audit recovery", getprogname()); 655 else 656 return (ADE_INVAL); 657 if (autext == NULL) 658 return (ADE_NOMEM); 659 660 if ((aufd = au_open()) == -1) { 661 free(autext); 662 return (ADE_AU_OPEN); 663 } 664 bzero(&aia, sizeof(aia)); 665 uid = getuid(); pid = getpid(); 666 if ((tok = au_to_subject32_ex(uid, geteuid(), getegid(), uid, getgid(), 667 pid, pid, &aia.ai_termid)) != NULL) 668 au_write(aufd, tok); 669 if ((tok = au_to_text(autext)) != NULL) 670 au_write(aufd, tok); 671 free(autext); 672 if (path != NULL && (tok = au_to_path(path)) != NULL) 673 au_write(aufd, tok); 674 if ((tok = au_to_return32(0, 0)) != NULL) 675 au_write(aufd, tok); 676 if (au_close(aufd, 1, event) == -1) 677 return (ADE_AU_CLOSE); 678 679 return (ADE_NOERR); 680} 681 682/* 683 * Check for a 'current' symlink and do crash recovery, if needed. Create a new 684 * 'current' symlink. The argument 'curfile' is the file the 'current' symlink 685 * should point to. Returns: 686 * ADE_NOERR on success, 687 * ADE_AU_OPEN if au_open(3) fails, 688 * ADE_AU_CLOSE if au_close(3) fails. 689 * ADE_RENAME if error renaming audit trail file, 690 * ADE_READLINK if error reading the 'current' link, 691 * ADE_SYMLINK if error creating 'current' link. 692 */ 693int 694auditd_new_curlink(char *curfile) 695{ 696 int len, err; 697 char *ptr; 698 char *path = NULL; 699 struct stat sb; 700 char recoveredname[MAXPATHLEN]; 701 char newname[MAXPATHLEN]; 702 703 /* 704 * Check to see if audit was shutdown properly. If not, clean up, 705 * recover previous audit trail file, and generate audit record. 706 */ 707 len = readlink(AUDIT_CURRENT_LINK, recoveredname, MAXPATHLEN - 1); 708 if (len > 0) { 709 /* 'current' exist but is it pointing at a valid file? */ 710 recoveredname[len++] = '\0'; 711 if (stat(recoveredname, &sb) == 0) { 712 /* Yes, rename it to a crash recovery file. */ 713 strlcpy(newname, recoveredname, MAXPATHLEN); 714 715 if ((ptr = strstr(newname, NOT_TERMINATED)) != NULL) { 716 strlcpy(ptr, CRASH_RECOVERY, TIMESTAMP_LEN); 717 if (rename(recoveredname, newname) != 0) 718 return (ADE_RENAME); 719 } else 720 return (ADE_STRERR); 721 722 path = newname; 723 } 724 725 /* 'current' symlink is (now) invalid so remove it. */ 726 (void) unlink(AUDIT_CURRENT_LINK); 727 728 /* Note the crash recovery in current audit trail */ 729 err = auditd_gen_record(AUE_audit_recovery, path); 730 if (err) 731 return (err); 732 } 733 734 if (len < 0 && errno != ENOENT) 735 return (ADE_READLINK); 736 737 if (symlink(curfile, AUDIT_CURRENT_LINK) != 0) 738 return (ADE_SYMLINK); 739 740 return (0); 741} 742 743/* 744 * Do just what we need to quickly start auditing. Assume no system logging or 745 * notify. Return: 746 * 0 on success, 747 * -1 on failure. 748 */ 749int 750audit_quick_start(void) 751{ 752 int err; 753 char *newfile; 754 time_t tt; 755 char TS[TIMESTAMP_LEN]; 756 757 /* 758 * Mask auditing of this process. 759 */ 760 if (auditd_prevent_audit() != 0) 761 return (-1); 762 763 /* 764 * Read audit_control and get log directories. 765 */ 766 err = auditd_read_dirs(NULL, NULL); 767 if (err != ADE_NOERR && err != ADE_SOFTLIM) 768 return (-1); 769 770 /* 771 * Create a new audit trail log. 772 */ 773 if (getTSstr(tt, TS, TIMESTAMP_LEN) != 0) 774 return (-1); 775 err = auditd_swap_trail(TS, &newfile, getgid(), NULL); 776 if (err != ADE_NOERR && err != ADE_ACTL) 777 return (-1); 778 779 /* 780 * Add the current symlink and recover from crash, if needed. 781 */ 782 if (auditd_new_curlink(newfile) != 0) 783 return(-1); 784 785 /* 786 * At this point auditing has started so generate audit start-up record. 787 */ 788 if (auditd_gen_record(AUE_audit_startup, NULL) != 0) 789 return (-1); 790 791 /* 792 * Configure the audit controls. 793 */ 794 (void) auditd_set_evcmap(); 795 (void) auditd_set_namask(); 796 (void) auditd_set_policy(); 797 (void) auditd_set_fsize(); 798 (void) auditd_set_minfree(); 799 (void) auditd_set_host(); 800 801 return (0); 802} 803 804/* 805 * Shut down auditing quickly. Assumes that is only called on system shutdown. 806 * Returns: 807 * 0 on success, 808 * -1 on failure. 809 */ 810int 811audit_quick_stop(void) 812{ 813 int len; 814 long cond; 815 char *ptr; 816 time_t tt; 817 char oldname[MAXPATHLEN]; 818 char newname[MAXPATHLEN]; 819 char TS[TIMESTAMP_LEN]; 820 821 /* 822 * Auditing already disabled? 823 */ 824 if (auditon(A_GETCOND, &cond, sizeof(cond)) < 0) 825 return (-1); 826 if (cond == AUC_NOAUDIT) 827 return (0); 828 829 /* 830 * Generate audit shutdown record. 831 */ 832 (void) auditd_gen_record(AUE_audit_shutdown, NULL); 833 834 /* 835 * Shutdown auditing in the kernel. 836 */ 837 cond = AUC_DISABLED; 838 if (auditon(A_SETCOND, &cond, sizeof(cond)) != 0) 839 return (-1); 840#ifdef __BSM_INTERNAL_NOTIFY_KEY 841 notify_post(__BSM_INTERNAL_NOTIFY_KEY); 842#endif 843 844 /* 845 * Rename last audit trail and remove 'current' link. 846 */ 847 len = readlink(AUDIT_CURRENT_LINK, oldname, MAXPATHLEN - 1); 848 if (len < 0) 849 return (-1); 850 oldname[len++] = '\0'; 851 852 if (getTSstr(tt, TS, TIMESTAMP_LEN) != 0) 853 return (-1); 854 855 strlcpy(newname, oldname, len); 856 857 if ((ptr = strstr(newname, NOT_TERMINATED)) != NULL) { 858 strlcpy(ptr, TS, TIMESTAMP_LEN); 859 if (rename(oldname, newname) != 0) 860 return (-1); 861 } else 862 return (-1); 863 864 (void) unlink(AUDIT_CURRENT_LINK); 865 866 return (0); 867} 868