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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE --- 45 unchanged lines hidden (view full) --- 54#include <sys/param.h> 55#include <sys/socket.h> 56#include <sys/types.h> 57#include <unistd.h> 58#include <poll.h> 59 60#include "audit_remote.h" 61 |
62#define DEFAULT_TIMEOUT 5 /* default connection timeout (in secs) */ 63#define NOSUCCESS_DELAY 20 /* unsuccessful delivery to all p_hosts */ 64 65#define FL_SET B_TRUE /* set_fdfl(): set the flag */ 66#define FL_UNSET B_FALSE /* set_fdfl(): unset the flag */ 67 68static int nosuccess_cnt; /* unsuccessful delivery counter */ 69 |
70static int retries; /* connection retries */ 71int timeout; /* connection timeout */ 72static int timeout_p_timeout; /* p_timeout attr storage */ |
73 |
74/* semi-exponential timeout back off; x .. attempts, y .. timeout */ 75#define BOFF_TIMEOUT(x, y) (x < 3 ? y * 2 * x : y * 8) 76 77/* general plugin lock */ 78pthread_mutex_t plugin_mutex = PTHREAD_MUTEX_INITIALIZER; 79 80static struct hostlist_s *current_host; 81static struct hostlist_s *hosts; |
82static struct hostlist_s *hosts_prev; |
83 84extern struct transq_hdr_s transq_hdr; 85static long transq_count_max; 86extern pthread_mutex_t transq_lock; 87 88extern pthread_t recv_tid; 89 90extern boolean_t notify_pipe_ready; 91extern int notify_pipe[2]; 92 93#if DEBUG 94FILE *dfile; /* debug file */ 95#endif 96 97/* 98 * set_transq_count_max() - sets the transq_count_max value based on kernel 99 * audit queue high water mark. This is backup solution for a case, when the |
100 * the default qsize zero value is (intentionally) set in the audit_remote(5) 101 * plugin configuration. |
102 */ 103static auditd_rc_t 104set_transq_count_max() 105{ 106 struct au_qctrl qctrl; 107 108 if (auditon(A_GETQCTRL, (caddr_t)&qctrl, 0) != -1) { 109 transq_count_max = qctrl.aq_hiwater; --- 62 unchanged lines hidden (view full) --- 172 while (str_end > str_ptr && isspace(str_end[-1])) { 173 str_end--; 174 } 175 *str_end = '\0'; 176 177 return (str_ptr); 178} 179 |
180/* 181 * Frees host list - should be called while keeping auditd_mutex. 182 */ 183static void 184freehostlist(hostlist_t **hostlist_ptr) 185{ 186 hostlist_t *h, *n; |
187 |
188 h = *hostlist_ptr; 189 190 while (h != NULL) { 191 n = h->next_host; 192 freehostent(h->host); 193 free(h); 194 h = n; 195 } 196 *hostlist_ptr = NULL; 197} 198 |
199/* 200 * parsehosts() end parses the host string (hosts_str) 201 */ 202static auditd_rc_t 203parsehosts(char *hosts_str, char **error) 204{ 205 char *hostportmech, *hpm; 206 char *hostname; 207 char *port_str; 208 char *mech_str; 209 int port; 210 int port_default = -1; 211 gss_OID mech_oid; 212 char *lasts_hpm; 213 hostlist_t *lasthost = NULL; |
214 hostlist_t *hosts_new = NULL; |
215 hostlist_t *newhost; 216 struct hostent *hostentry; 217 int error_num; 218 int rc; 219#if DEBUG 220 char addr_buf[INET6_ADDRSTRLEN]; 221 int num_of_hosts = 0; 222#endif 223 |
224 DPRINT((dfile, "parsing %s\n", hosts_str)); 225 while ((hostportmech = strtok_r(hosts_str, ",", &lasts_hpm)) != NULL) { 226 227 hosts_str = NULL; 228 hostname = NULL; 229 port_str = NULL; 230 port = port_default; 231 mech_str = NULL; --- 111 unchanged lines hidden (view full) --- 343 newhost->port = htons(port); 344 newhost->mech = mech_oid; 345 newhost->next_host = NULL; 346 if (lasthost != NULL) { 347 lasthost->next_host = newhost; 348 lasthost = lasthost->next_host; 349 } else { 350 lasthost = newhost; |
351 hosts_new = newhost; |
352 } 353#if DEBUG 354 num_of_hosts++; 355#endif 356 } 357 |
358 (void) pthread_mutex_lock(&plugin_mutex); 359 if (hosts_prev == NULL) { 360 hosts_prev = hosts; 361 } 362 hosts = hosts_new; |
363 current_host = hosts; |
364 (void) pthread_mutex_unlock(&plugin_mutex); 365 |
366 DPRINT((dfile, "Configured %d hosts.\n", num_of_hosts)); 367 368 return (AUDITD_SUCCESS); 369} 370 371 |
372#if DEBUG 373static char * 374auditd_message(auditd_rc_t msg_code) { 375 char *rc_msg; 376 377 switch (msg_code) { 378 case AUDITD_SUCCESS: 379 rc_msg = strdup("ok"); --- 222 unchanged lines hidden (view full) --- 602 sequence, &err_rsn); 603 DPRINT((dfile, "send_record() returned %d - ", send_record_rc)); 604 605 switch (send_record_rc) { 606 case SEND_RECORD_SUCCESS: 607 DPRINT((dfile, "success\n")); 608 nosuccess_cnt = 0; 609 rc = AUDITD_SUCCESS; |
610 if (hosts_prev != NULL) { 611 freehostlist(&hosts_prev); 612 DPRINT((dfile, "stale host list freed\n")); 613 } |
614 break; 615 case SEND_RECORD_NEXT: |
616 DPRINT((dfile, "retry the same host: %s (penalty) " 617 "rsn:%d\n", current_host->host->h_name, err_rsn)); |
618 attempts++; 619 break; 620 case SEND_RECORD_RETRY: |
621 DPRINT((dfile, "retry the same host: %s (no penalty) " 622 "rsn:%d\n", current_host->host->h_name, err_rsn)); |
623 break; 624 } 625 |
626 if (send_record_rc == SEND_RECORD_NEXT) { 627 628 /* warn about unsuccessful auditd record delivery */ 629 rsn_msg = rsn_to_msg(err_rsn); 630 (void) asprintf(&ext_error, 631 "retry %d connection %s:%d %s", attempts + 1, 632 current_host->host->h_name, 633 ntohs(current_host->port), rsn_msg); 634 if (ext_error == NULL) { 635 free(rsn_msg); 636 *error = strdup(gettext("no memory")); 637 rc = AUDITD_NO_MEMORY; 638 break; 639 } 640 __audit_dowarn2("plugin", "audit_remote.so", "retry", 641 ext_error, attempts + 1); 642 free(rsn_msg); 643 free(ext_error); 644 |
645 if (attempts < retries) { 646 /* semi-exponential timeout back off */ 647 timeout = BOFF_TIMEOUT(attempts, timeout); 648 DPRINT((dfile, "New timeout=%d\n", timeout)); 649 } else { 650 /* get next host */ 651 current_host = current_host->next_host; 652 if (current_host == NULL) { 653 current_host = hosts; 654 } |
655 timeout = timeout_p_timeout; |
656 DPRINT((dfile, "New timeout=%d\n", timeout)); 657 attempts = 0; 658 } 659 |
660 /* one cycle finished */ 661 if (current_host == start_host && attempts == 0) { 662 nosuccess_cnt++; 663 (void) asprintf(&ext_error, "all hosts defined " 664 "as p_hosts were tried to deliver " 665 "the audit record to with no success " 666 "- sleeping for %d seconds", 667 NOSUCCESS_DELAY); --- 50 unchanged lines hidden (view full) --- 718#if DEBUG 719 dfile = __auditd_debug_file_open(); 720#endif 721 722 /* initial open or audit -s */ 723 if (kvlist != NULL) { 724 DPRINT((dfile, "Action: initial open or `audit -s`\n")); 725 val_str = kva_match(kv, "p_timeout"); |
726 if (val_str == NULL) { 727 *error = strdup( 728 gettext("p_timeout attribute not found")); 729 return (AUDITD_RETRY); |
730 } |
731 DPRINT((dfile, "val_str=%s\n", val_str)); 732 errno = 0; 733 val = atoi(val_str); 734 if (errno == 0 && val >= 1) { 735 timeout_p_timeout = val; 736 timeout = val; 737 } else { 738 timeout_p_timeout = DEFAULT_TIMEOUT; 739 timeout = timeout_p_timeout; 740 DPRINT((dfile, "p_timeout set to default value: %d\n", 741 timeout)); 742 } |
743 744 val_str = kva_match(kv, "p_retries"); |
745 if (val_str == NULL) { 746 *error = strdup( 747 gettext("p_retries attribute not found")); 748 return (AUDITD_RETRY); |
749 } |
750 DPRINT((dfile, "val_str=%s\n", val_str)); 751 errno = 0; 752 val = atoi(val_str); 753 if (errno == 0 && val >= 0) { 754 retries = val; 755 } |
756 757 val_str = kva_match(kv, "qsize"); |
758 if (val_str == NULL) { 759 *error = strdup(gettext("qsize attribute not found")); 760 return (AUDITD_RETRY); |
761 } |
762 DPRINT((dfile, "qsize=%s\n", val_str)); 763 errno = 0; 764 val_l = atol(val_str); 765 if (errno == 0 && val_l >= 0) { 766 transq_count_max = val_l; 767 } 768 if (transq_count_max == 0 && 769 (rc = set_transq_count_max()) != AUDITD_SUCCESS) { 770 *error = strdup(gettext("cannot get kernel " 771 "auditd queue high water mark\n")); 772 return (rc); 773 } |
774 DPRINT((dfile, "timeout=%d, retries=%d, transq_count_max=%ld\n", 775 timeout, retries, transq_count_max)); 776 777 val_str = kva_match(kv, "p_hosts"); 778 if (val_str == NULL) { 779 *error = strdup(gettext("no hosts configured")); 780 return (AUDITD_RETRY); 781 } --- 32 unchanged lines hidden (view full) --- 814auditd_plugin_close(char **error) 815{ 816 reset_transport(DO_EXIT, DO_SYNC); 817 if (pthread_join(recv_tid, NULL) != 0) { 818 *error = strdup(gettext("unable to close receiving thread")); 819 return (AUDITD_RETRY); 820 } 821 |
822 (void) pthread_mutex_lock(&plugin_mutex); 823 freehostlist(&hosts); 824 freehostlist(&hosts_prev); 825 (void) pthread_mutex_unlock(&plugin_mutex); 826 current_host = NULL; |
827 *error = NULL; 828 return (AUDITD_SUCCESS); 829} |