1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* Audit daemon server */ 30 /* 31 * These routines make up the audit daemon server. This daemon, called 32 * auditd, handles the user level parts of auditing. It receives buffered 33 * audit records (usually one or more per buffer, potentially less than 34 * one) and passes them to one or more plugins for processing. 35 * 36 * The major interrupts are AU_SIG_READ_CONTROL (start over), 37 * AU_SIG_DISABLE (start shutting down), SIGALRM (quit), and 38 * AU_SIG_NEXT_DIR (start a new audit log file). SIGTERM (the implementation 39 * value of AU_SIG_DISABLE) is also used for the child to tell the parent 40 * that audit is ready. 41 * 42 * Configuration data comes from /etc/security/audit_control and the auditon 43 * system call. 44 * 45 * The major errors are EBUSY (auditing is already in use) and EINTR 46 * (one of the above signals was received). File space errors are 47 * handled by the audit_binfile plugin 48 */ 49 50 #define DEBUG 0 51 #define MEM_TEST 0 /* set to one to generate core dump on exit */ 52 53 #include <assert.h> 54 #include <bsm/audit.h> 55 #include <bsm/audit_record.h> 56 #include <bsm/libbsm.h> 57 #include <fcntl.h> 58 #include <libintl.h> 59 #include <locale.h> 60 #include <netdb.h> 61 #include <pwd.h> 62 #include <secdb.h> 63 #include <signal.h> 64 #include <stdio.h> 65 #include <stdlib.h> 66 #include <string.h> 67 #include <errno.h> 68 #include <sys/file.h> 69 #include <sys/param.h> 70 #include <sys/stat.h> 71 #include <sys/statvfs.h> 72 #include <sys/time.h> 73 #include <sys/types.h> 74 #include <sys/wait.h> 75 #include <termios.h> 76 #include <unistd.h> 77 #include "plugin.h" 78 #include "audit_sig_infc.h" 79 #include <audit_plugin.h> 80 81 #if !defined(TEXT_DOMAIN) 82 #define TEXT_DOMAIN "SUNW_OST_OSCMD" 83 #endif 84 /* 85 * After we get a AU_SIG_DISABLE, we want to set a timer for 2 seconds 86 * and let c2audit write as many records as it can until the timer 87 * goes off(at which point it returns to auditd with SIGALRM). If any 88 * other signals are received during that time, we call 89 * __audit_dowarn() to indicate that the queue may not have been fully 90 * flushed. 91 */ 92 #define ALRM_TIME 2 93 #define SLEEP_TIME 20 /* # of seconds to sleep in all hard loop */ 94 95 #if DEBUG 96 #define DPRINT(x) {(void) fprintf x; } 97 static FILE *dbfp; /* debug file */ 98 #else 99 #define DPRINT(x) 100 #endif /* DEBUG */ 101 102 static plugin_t *binfile = NULL; 103 104 static int turn_audit_on = AUC_AUDITING; 105 static int turn_audit_off = AUC_NOAUDIT; 106 107 static int running = 1; 108 109 /* 110 * GLOBALS: 111 */ 112 plugin_t *plugin_head = NULL; 113 static thr_data_t main_thr; /* auditd thread (0) */ 114 pthread_mutex_t plugin_mutex; /* for plugin_t list */ 115 116 static int caught_alrm = 0; /* number of SIGALRMs pending */ 117 static int caught_readc = 0; /* number of AU_SIG_READ_CONTROLs */ 118 static int caught_term = 0; /* number of AU_SIG_DISABLEs pending */ 119 static int caught_nextd = 0; /* number of AU_SIG_NEXT_DIRs pending */ 120 121 static int reset_list = 1; /* 1 to re-read audit_control */ 122 static int reset_file = 1; /* 1 to close/open binary log */ 123 124 static int auditing_set = 0; /* 1 if auditon(A_SETCOND, on... */ 125 126 static void my_sleep(); 127 static void signal_thread(); 128 static void loadauditlist(); 129 static void block_signals(); 130 static int do_sethost(); 131 132 /* common exit function */ 133 void 134 auditd_exit(int status) 135 { 136 #if MEM_TEST 137 sigset_t set; 138 139 DPRINT((dbfp, "mem_test intentional abort (status=%d)\n", 140 status)); 141 abort(); 142 #endif 143 DPRINT((dbfp, "%ld exit status = %d auditing_set = %d\n", 144 getpid(), status, auditing_set)); 145 146 if (auditing_set) 147 (void) auditon(A_SETCOND, (caddr_t)&turn_audit_off, 148 (int)sizeof (int)); 149 150 exit(status); 151 } 152 153 /* ARGSUSED */ 154 main(int argc, char *argv[]) 155 { 156 auditinfo_addr_t as_null; /* audit state to set */ 157 au_id_t auid; 158 pthread_t tid; 159 plugin_t *p; 160 pid_t pid; 161 162 #if DEBUG 163 /* LINTED */ 164 char *envp; 165 dbfp = __auditd_debug_file_open(); 166 #endif 167 (void) setsid(); 168 169 /* Internationalization */ 170 (void) setlocale(LC_ALL, ""); 171 (void) textdomain(TEXT_DOMAIN); 172 173 /* 174 * Set the audit host-id. 175 */ 176 if (do_sethost() != 0) { 177 __audit_dowarn("nostart", "", 0); 178 auditd_exit(1); 179 } 180 181 /* 182 * Turn off all auditing for this process. 183 */ 184 if (getaudit_addr(&as_null, sizeof (as_null)) == -1) { 185 __audit_dowarn("nostart", "", 0); 186 auditd_exit(2); 187 } 188 as_null.ai_mask.as_success = 0; 189 as_null.ai_mask.as_failure = 0; 190 (void) setaudit_addr(&as_null, sizeof (as_null)); 191 auid = AU_NOAUDITID; 192 (void) setauid(&auid); 193 /* 194 * Set the audit state flag to AUDITING. 195 */ 196 if (auditon(A_SETCOND, (caddr_t)&turn_audit_on, (int)sizeof (int)) != 197 0) { 198 DPRINT((dbfp, "auditon(A_SETCOND...) failed (exit)\n")); 199 __audit_dowarn("nostart", "", 0); 200 auditd_exit(7); 201 } 202 203 block_signals(); 204 205 #if DEBUG 206 /* output to dbfp shouldn't be duplicated by parent and child */ 207 (void) fflush(dbfp); 208 #endif 209 /* 210 * wait for "ready" signal before exit -- for greenline 211 */ 212 if (fork()) { 213 sigset_t set; 214 int signal_caught = 0; 215 216 (void) sigemptyset(&set); 217 (void) sigaddset(&set, AU_SIG_DISABLE); 218 219 while (signal_caught != AU_SIG_DISABLE) 220 signal_caught = sigwait(&set); 221 222 DPRINT((dbfp, "init complete: parent can now exit\n")); 223 224 auditd_exit(0); 225 } 226 pid = getppid(); 227 228 auditing_set = 1; 229 230 #if DEBUG && MEM_TEST 231 envp = getenv("UMEM_DEBUG"); 232 if (envp != NULL) 233 DPRINT((dbfp, "UMEM_DEBUG=%s\n", envp)); 234 envp = getenv("UMEM_LOGGING"); 235 if (envp != NULL) 236 DPRINT((dbfp, "UMEM_LOGGING=%s\n", envp)); 237 #endif 238 DPRINT((dbfp, "auditd pid=%ld\n", getpid())); 239 240 /* thread 0 sync */ 241 (void) pthread_mutex_init(&(main_thr.thd_mutex), NULL); 242 (void) pthread_cond_init(&(main_thr.thd_cv), NULL); 243 (void) pthread_mutex_init(&plugin_mutex, NULL); 244 /* 245 * Set up a separate thread for signal handling. 246 */ 247 if (pthread_create(&tid, NULL, (void *(*)(void *))signal_thread, 248 NULL)) { 249 (void) fprintf(stderr, gettext( 250 "auditd can't create a thread\n")); 251 auditd_exit(3); 252 } 253 /* 254 * Set the umask so that only audit or other users in the audit group 255 * can get to the files created by auditd. 256 */ 257 (void) umask(007); 258 259 if (__logpost("")) { /* Open the audit_data file. */ 260 DPRINT((dbfp, "logpost failed\n")); 261 auditd_exit(4); 262 } 263 /* 264 * Here is the main body of the audit daemon. running == 0 means that 265 * after flushing out the audit queue, it is time to exit in response to 266 * AU_SIG_DISABLE 267 */ 268 while (running) { 269 /* 270 * Read audit_control and create plugin lists. 271 * 272 * loadauditlist() and auditd_thread_init() are called 273 * while under the plugin_mutex lock to avoid a race 274 * with unload_plugin(). 275 */ 276 if (reset_list || reset_file) { 277 (void) pthread_mutex_lock(&plugin_mutex); 278 if (reset_list) 279 loadauditlist(); 280 281 if (auditd_thread_init()) { 282 auditd_thread_close(); 283 /* continue; wait for audit -s */ 284 } 285 (void) pthread_mutex_unlock(&plugin_mutex); 286 reset_list = 0; 287 } 288 /* 289 * tell parent I'm running whether or not the initialization 290 * actually worked. The failure case is to wait for an 291 * audit -n or audit -s to fix the problem. 292 */ 293 if (pid != 0) { 294 (void) kill(pid, AU_SIG_DISABLE); 295 pid = 0; 296 } 297 /* 298 * thread_signal() signals main (this thread) when 299 * it has received a signal. 300 */ 301 DPRINT((dbfp, "main thread is waiting\n")); 302 (void) pthread_mutex_lock(&(main_thr.thd_mutex)); 303 304 if (!(caught_readc || caught_term || caught_alrm || 305 caught_nextd)) 306 (void) pthread_cond_wait(&(main_thr.thd_cv), 307 &(main_thr.thd_mutex)); 308 (void) pthread_mutex_unlock(&(main_thr.thd_mutex)); 309 /* 310 * Got here because a signal came in. 311 * Since we may have gotten more than one, we assume a 312 * priority scheme with SIGALRM being the most 313 * significant. 314 */ 315 if (caught_alrm) { 316 /* 317 * We have returned from our timed wait for 318 * c2audit to calm down. We need to really shut 319 * down here. 320 */ 321 caught_alrm = 0; 322 running = 0; /* shut down now */ 323 } else if (caught_term) { 324 /* 325 * we are going to shut down, but need to 326 * allow time for the audit queues in 327 * c2audit and for the threads to empty. 328 */ 329 330 p = plugin_head; 331 while (p != NULL) { 332 DPRINT((dbfp, "signalling thread %d\n", 333 p->plg_tid)); 334 (void) pthread_mutex_lock(&(p->plg_mutex)); 335 p->plg_removed = 1; 336 337 if (p->plg_initialized) 338 (void) pthread_cond_signal( 339 &(p->plg_cv)); 340 341 (void) pthread_mutex_unlock(&(p->plg_mutex)); 342 p = p->plg_next; 343 } 344 345 caught_alrm = 0; 346 caught_readc = 0; 347 caught_term = 0; 348 caught_nextd = 0; 349 350 DPRINT((dbfp, 351 "main thread is pausing before exit.\n")); 352 (void) pthread_mutex_lock(&(main_thr.thd_mutex)); 353 caught_alrm = 0; 354 (void) alarm(ALRM_TIME); 355 while (!caught_alrm) 356 (void) pthread_cond_wait(&(main_thr.thd_cv), 357 &(main_thr.thd_mutex)); 358 359 (void) pthread_mutex_unlock(&(main_thr.thd_mutex)); 360 361 running = 0; /* Close down auditing and exit */ 362 } else if (caught_readc) { 363 /* 364 * if both hup and usr1 are caught, the logic in 365 * loadauditlist() results in hup winning. The 366 * result will be that the audit file is not rolled 367 * over unless audit_control actually changed. 368 * 369 * They want to reread the audit_control file. 370 * Set reset_list which will return us to the 371 * main while loop in the main routine. 372 */ 373 caught_readc = 0; 374 reset_list = 1; 375 } else if (caught_nextd) { 376 /* 377 * This is a special case for the binfile 378 * plugin. (audit -n) NULL out kvlist 379 * so binfile won't re-read audit_control 380 */ 381 caught_nextd = 0; 382 reset_file = 1; 383 if (binfile != NULL) { 384 _kva_free(binfile->plg_kvlist); 385 binfile->plg_kvlist = NULL; 386 binfile->plg_reopen = 1; 387 } 388 } 389 } /* end while (running) */ 390 auditd_thread_close(); 391 392 auditd_exit(0); 393 return (0); 394 } 395 396 /* 397 * my_sleep - sleep for SLEEP_TIME seconds but only accept the signals 398 * that we want to accept. (Premature termination just means the 399 * caller retries more often, not a big deal.) 400 */ 401 402 static void 403 my_sleep() 404 { 405 DPRINT((dbfp, "auditd: sleeping for 20 seconds\n")); 406 /* 407 * Set timer to "sleep" 408 */ 409 (void) alarm(SLEEP_TIME); 410 411 DPRINT((dbfp, "main thread is waiting for SIGALRM before exit.\n")); 412 (void) pthread_mutex_lock(&(main_thr.thd_mutex)); 413 (void) pthread_cond_wait(&(main_thr.thd_cv), &(main_thr.thd_mutex)); 414 (void) pthread_mutex_unlock(&(main_thr.thd_mutex)); 415 416 if (caught_term) { 417 DPRINT((dbfp, "normal AU_SIG_DISABLE exit\n")); 418 /* 419 * Exit, as requested. 420 */ 421 auditd_thread_close(); 422 } 423 if (caught_readc) 424 reset_list = 1; /* Reread the audit_control file */ 425 426 caught_readc = 0; 427 caught_nextd = 0; 428 } 429 430 /* 431 * search for $ISA/ in path and replace it with "" if auditd 432 * is 32 bit, else "sparcv9/" The plugin $ISA must match however 433 * auditd was compiled. 434 */ 435 436 static void 437 isa_ified(char *path, char **newpath) 438 { 439 char *p, *q; 440 441 if (((p = strchr(path, '$')) != NULL) && 442 (strncmp("$ISA/", p, 5) == 0)) { 443 (void) memcpy(*newpath, path, p - path); 444 q = *newpath + (p - path); 445 #ifdef __sparcv9 446 q += strlcpy(q, "sparcv9/", avail_length); 447 #endif 448 (void) strcpy(q, p + 5); 449 } else 450 *newpath = path; 451 } 452 453 /* 454 * init_plugin first searches the existing plugin list to see 455 * if the plugin already has been defined; if not, it creates it 456 * and links it into the list. It returns a pointer to the found 457 * or created struct. A change of path in audit_control for a 458 * given plugin will cause a miss. 459 */ 460 /* 461 * for 64 bits, the path name can grow 3 bytes (minus 5 for the 462 * removed "$ISA" and plus 8 for the added "sparcv9/" 463 */ 464 465 #define ISA_GROW 8 - 5 466 467 static plugin_t * 468 init_plugin(char *name, kva_t *list, int cnt_flag) 469 { 470 plugin_t *p, *q; 471 char filepath[MAXPATHLEN + 1 + ISA_GROW]; 472 char *path = filepath; 473 474 if (*name != '/') { 475 #ifdef __sparcv9 476 (void) strcpy(filepath, "/usr/lib/security/sparcv9/"); 477 #else 478 (void) strcpy(filepath, "/usr/lib/security/"); 479 #endif 480 if (strlcat(filepath, name, MAXPATHLEN) >= MAXPATHLEN) 481 return (NULL); 482 } else { 483 if (strlen(name) > MAXPATHLEN + ISA_GROW) 484 return (NULL); 485 isa_ified(name, &path); 486 } 487 p = plugin_head; 488 q = plugin_head; 489 while (p != NULL) { 490 if (p->plg_path != NULL) { 491 if (strcmp(p->plg_path, path) == 0) { 492 p->plg_removed = 0; 493 p->plg_to_be_removed = 0; 494 p->plg_cnt = cnt_flag; 495 496 _kva_free(p->plg_kvlist); 497 p->plg_kvlist = list; 498 p->plg_reopen = 1; 499 DPRINT((dbfp, "reusing %s\n", p->plg_path)); 500 return (p); 501 } 502 } 503 q = p; 504 p = p->plg_next; 505 } 506 DPRINT((dbfp, "creating new plugin structure for %s\n", path)); 507 508 p = malloc(sizeof (plugin_t)); 509 510 if (p == NULL) { 511 perror("auditd"); 512 return (NULL); 513 } 514 if (q == NULL) 515 plugin_head = p; 516 else 517 q->plg_next = p; 518 519 p->plg_next = NULL; 520 p->plg_initialized = 0; 521 p->plg_reopen = 1; 522 p->plg_tid = 0; 523 p->plg_removed = 0; 524 p->plg_to_be_removed = 0; 525 p->plg_tossed = 0; 526 p->plg_queued = 0; 527 p->plg_output = 0; 528 p->plg_sequence = 1; 529 p->plg_last_seq_out = 0; 530 p->plg_path = strdup(path); 531 p->plg_kvlist = list; 532 p->plg_cnt = cnt_flag; 533 p->plg_retry_time = SLEEP_TIME; 534 p->plg_qmax = 0; 535 p->plg_save_q_copy = NULL; 536 537 DPRINT((dbfp, "created plugin: %s\n", path)); 538 return (p); 539 } 540 541 /* 542 * loadauditlist - read the directory list from the audit_control file. 543 * to determine if a binary file is to be written. 544 * - read the plugin entries from the audit_control file 545 * 546 * globals - 547 * 548 * plugin queues 549 * 550 * success is when at least one plug in is defined. 551 * 552 * set cnt policy here based on auditconfig setting. future could 553 * have a policy = {+|-}cnt entry per plugin with auditconfig providing the 554 * default. 555 */ 556 557 static void 558 loadauditlist() 559 { 560 char buf[MAXPATHLEN]; 561 char *value; 562 plugin_t *p; 563 int acresult; 564 int wait_count = 0; 565 kva_t *kvlist; 566 long policy; 567 int cnt_flag; 568 struct au_qctrl kqmax; 569 au_acinfo_t *ach = NULL; 570 int got_dir = 0; 571 int have_plugin = 0; 572 char *endptr; 573 574 if (auditon(A_GETPOLICY, (char *)&policy, 0) == -1) { 575 DPRINT((dbfp, "auditon(A_GETPOLICY...) failed (exit)\n")); 576 __audit_dowarn("auditoff", "", 0); 577 auditd_thread_close(); 578 auditd_exit(5); 579 } 580 cnt_flag = ((policy & AUDIT_CNT) != 0) ? 1 : 0; 581 DPRINT((dbfp, "loadauditlist: policy is to %s\n", (cnt_flag == 1) ? 582 "continue" : "block")); 583 584 #if DEBUG 585 if (auditon(A_GETCOND, (caddr_t)&acresult, (int)sizeof (int)) != 586 0) 587 DPRINT((dbfp, "auditon(A_GETCOND...) failed (exit)\n")); 588 #endif 589 DPRINT((dbfp, "audit cond = %d (1 is on)\n", acresult)); 590 591 592 if (auditon(A_GETQCTRL, (char *)&kqmax, sizeof (struct au_qctrl)) != 593 0) { 594 DPRINT((dbfp, "auditon(A_GETQCTRL...) failed (exit)\n")); 595 __audit_dowarn("auditoff", "", 0); 596 auditd_thread_close(); 597 auditd_exit(6); 598 } 599 kqmax.aq_hiwater *= 5; /* RAM is cheaper in userspace */ 600 DPRINT((dbfp, "auditd: reading audit_control\n")); 601 602 p = plugin_head; 603 /* 604 * two-step on setting p->plg_removed because the input thread 605 * in doorway.c uses p->plg_removed to decide if the plugin is 606 * active. 607 */ 608 while (p != NULL) { 609 DPRINT((dbfp, "loadauditlist: %X, %s previously created\n", 610 p, p->plg_path)); 611 p->plg_to_be_removed = 1; /* tentative removal */ 612 p = p->plg_next; 613 } 614 /* 615 * have_plugin may over count by one if both a "dir" entry 616 * and a "plugin" entry for binfile are found. All that 617 * matters is that it be zero if no plugin or dir entries 618 * are found. 619 */ 620 have_plugin = 0; 621 for (;;) { 622 /* NULL == use standard path for audit_control */ 623 ach = _openac(NULL); 624 /* 625 * loop until a directory entry is found (0) or eof (-1) 626 */ 627 while (((acresult = _getacdir(ach, buf, sizeof (buf))) != 0) && 628 acresult != -1) { 629 } 630 if (acresult == 0) { 631 DPRINT((dbfp, 632 "loadauditlist: " 633 "got binfile via old config syntax\n")); 634 /* 635 * A directory entry was found. 636 */ 637 got_dir = 1; 638 kvlist = _str2kva("name=audit_binfile.so.1", 639 "=", ";"); 640 641 p = init_plugin("audit_binfile.so.1", kvlist, cnt_flag); 642 643 if (p != NULL) { 644 binfile = p; 645 p->plg_qmax = kqmax.aq_hiwater; 646 have_plugin++; 647 } 648 } 649 /* 650 * collect plugin entries. If there is an entry for 651 * binfile.so.1, the parameters from the plugin line 652 * override those set above. For binfile, p_dir is 653 * required only if dir wasn't specified elsewhere in 654 * audit_control 655 */ 656 _rewindac(ach); 657 while ((acresult = _getacplug(ach, &kvlist)) == 0) { 658 value = kva_match(kvlist, "name"); 659 if (value == NULL) 660 break; 661 DPRINT((dbfp, "loadauditlist: have an entry for %s\n", 662 value)); 663 p = init_plugin(value, kvlist, cnt_flag); 664 if (p == NULL) 665 continue; 666 667 if (strstr(value, "/audit_binfile.so") != NULL) { 668 binfile = p; 669 if (!got_dir && 670 (kva_match(kvlist, "p_dir") == 671 NULL)) { 672 __audit_dowarn("getacdir", "", 673 wait_count); 674 } 675 } 676 p->plg_qmax = kqmax.aq_hiwater; /* default */ 677 value = kva_match(kvlist, "qsize"); 678 if (value != NULL) { 679 long tmp; 680 681 tmp = strtol(value, &endptr, 10); 682 if (*endptr == '\0') 683 p->plg_qmax = tmp; 684 } 685 DPRINT((dbfp, "%s queue max = %d\n", 686 p->plg_path, p->plg_qmax)); 687 688 have_plugin++; 689 } 690 _endac(ach); 691 if (have_plugin != 0) 692 break; 693 /* 694 * there was a problem getting the directory 695 * list or remote host info from the audit_control file 696 */ 697 wait_count++; 698 #if DEBUG 699 if (wait_count < 2) 700 DPRINT((dbfp, 701 "auditd: problem getting directory " 702 "/ or plugin list from audit_control.\n")); 703 #endif /* DEBUG */ 704 __audit_dowarn("getacdir", "", wait_count); 705 /* 706 * sleep for SLEEP_TIME seconds. 707 */ 708 my_sleep(); 709 } /* end for(;;) */ 710 711 p = plugin_head; 712 while (p != NULL) { 713 DPRINT((dbfp, "loadauditlist: %s remove flag=%d; cnt=%d\n", 714 p->plg_path, p->plg_to_be_removed, p->plg_cnt)); 715 p->plg_removed = p->plg_to_be_removed; 716 p = p->plg_next; 717 } 718 } 719 720 /* 721 * block signals -- thread-specific blocking of the signals expected 722 * by the main thread. 723 */ 724 725 static void 726 block_signals() 727 { 728 sigset_t set; 729 730 (void) sigfillset(&set); 731 (void) pthread_sigmask(SIG_BLOCK, &set, NULL); 732 } 733 734 /* 735 * signal_thread is the designated signal catcher. It wakes up the 736 * main thread whenever it receives a signal and then goes back to 737 * sleep; it does not exit. The global variables caught_* let 738 * the main thread which signal was received. 739 * 740 * The thread is created with all signals blocked. 741 */ 742 743 static void 744 signal_thread() 745 { 746 sigset_t set; 747 int signal_caught; 748 749 DPRINT((dbfp, "the signal thread is thread %d\n", 750 pthread_self())); 751 752 (void) sigemptyset(&set); 753 (void) sigaddset(&set, SIGALRM); 754 (void) sigaddset(&set, AU_SIG_DISABLE); 755 (void) sigaddset(&set, AU_SIG_READ_CONTROL); 756 (void) sigaddset(&set, AU_SIG_NEXT_DIR); 757 758 for (;;) { 759 signal_caught = sigwait(&set); 760 switch (signal_caught) { 761 case SIGALRM: 762 caught_alrm++; 763 DPRINT((dbfp, "caught SIGALRM\n")); 764 break; 765 case AU_SIG_DISABLE: 766 caught_term++; 767 DPRINT((dbfp, "caught AU_SIG_DISABLE\n")); 768 break; 769 case AU_SIG_READ_CONTROL: 770 caught_readc++; 771 DPRINT((dbfp, "caught AU_SIG_READ_CONTROL\n")); 772 break; 773 case AU_SIG_NEXT_DIR: 774 caught_nextd++; 775 DPRINT((dbfp, "caught AU_SIG_NEXT_DIR\n")); 776 break; 777 default: 778 DPRINT((dbfp, "caught unexpected signal: %d\n", 779 signal_caught)); 780 break; 781 } 782 (void) pthread_cond_signal(&(main_thr.thd_cv)); 783 } 784 } 785 786 /* 787 * do_sethost - do auditon(2) to set the audit host-id. 788 * Returns 0 if success, error code or -1 otherwise. 789 */ 790 static int 791 do_sethost(void) 792 { 793 int err; 794 char host_name[MAXHOSTNAMELEN + 1]; 795 auditinfo_addr_t audit_info; 796 struct addrinfo hints; 797 struct addrinfo *ai; 798 int addr_type; 799 void *p; 800 801 /* First, get our machine name and convert to IP address */ 802 if ((err = gethostname(host_name, sizeof (host_name)))) { 803 return (err); 804 } 805 (void) memset(&hints, 0, sizeof (hints)); 806 hints.ai_family = PF_INET; 807 err = getaddrinfo(host_name, NULL, &hints, &ai); 808 if (err == 0) { 809 addr_type = AU_IPv4; 810 /* LINTED */ 811 p = &((struct sockaddr_in *)ai->ai_addr)->sin_addr; 812 } else { 813 hints.ai_family = PF_INET6; 814 err = getaddrinfo(host_name, NULL, &hints, &ai); 815 if (err != 0) { 816 return (-1); 817 } 818 addr_type = AU_IPv6; 819 /* LINTED */ 820 p = &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr; 821 } 822 823 /* Get current kernel audit info, and fill in the IP address */ 824 if ((err = auditon(A_GETKAUDIT, (caddr_t)&audit_info, 825 sizeof (audit_info))) < 0) { 826 return (err); 827 } 828 audit_info.ai_termid.at_type = addr_type; 829 (void) memcpy(&audit_info.ai_termid.at_addr[0], p, 830 addr_type); 831 832 freeaddrinfo(ai); 833 834 /* Update the kernel audit info with new IP address */ 835 if ((err = auditon(A_SETKAUDIT, (caddr_t)&audit_info, 836 sizeof (audit_info))) < 0) { 837 return (err); 838 } 839 840 return (0); 841 } 842