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