audit_remote.c (9fa473b0) | audit_remote.c (f8994074) |
---|---|
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 | 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_RETRIES 3 /* default connection retries */ | |
63#define DEFAULT_TIMEOUT 5 /* default connection timeout (in secs) */ 64#define NOSUCCESS_DELAY 20 /* unsuccessful delivery to all p_hosts */ 65 66#define FL_SET B_TRUE /* set_fdfl(): set the flag */ 67#define FL_UNSET B_FALSE /* set_fdfl(): unset the flag */ 68 69static int nosuccess_cnt; /* unsuccessful delivery counter */ 70 | 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 */ |
|
71 | 73 |
72static int retries = DEFAULT_RETRIES; /* connection retries */ 73int timeout = DEFAULT_TIMEOUT; /* connection timeout */ 74static int timeout_p_timeout = -1; /* p_timeout attr storage */ 75 76/* time reset mechanism; x .. timeout_p_timeout */ 77#define RST_TIMEOUT(x) (x != -1 ? x : DEFAULT_TIMEOUT) 78 | |
79/* semi-exponential timeout back off; x .. attempts, y .. timeout */ 80#define BOFF_TIMEOUT(x, y) (x < 3 ? y * 2 * x : y * 8) 81 82/* general plugin lock */ 83pthread_mutex_t plugin_mutex = PTHREAD_MUTEX_INITIALIZER; 84 85static struct hostlist_s *current_host; 86static struct hostlist_s *hosts; | 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; |
|
87 88extern struct transq_hdr_s transq_hdr; 89static long transq_count_max; 90extern pthread_mutex_t transq_lock; 91 92extern pthread_t recv_tid; 93 94extern boolean_t notify_pipe_ready; 95extern int notify_pipe[2]; 96 97#if DEBUG 98FILE *dfile; /* debug file */ 99#endif 100 101/* 102 * set_transq_count_max() - sets the transq_count_max value based on kernel 103 * audit queue high water mark. This is backup solution for a case, when the | 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 |
104 * plugin audit_control(4) option lacks (intentionally) the qsize option. | 100 * the default qsize zero value is (intentionally) set in the audit_remote(5) 101 * plugin configuration. |
105 */ 106static auditd_rc_t 107set_transq_count_max() 108{ 109 struct au_qctrl qctrl; 110 111 if (auditon(A_GETQCTRL, (caddr_t)&qctrl, 0) != -1) { 112 transq_count_max = qctrl.aq_hiwater; --- 62 unchanged lines hidden (view full) --- 175 while (str_end > str_ptr && isspace(str_end[-1])) { 176 str_end--; 177 } 178 *str_end = '\0'; 179 180 return (str_ptr); 181} 182 | 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; |
|
183 | 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 |
|
184/* 185 * parsehosts() end parses the host string (hosts_str) 186 */ 187static auditd_rc_t 188parsehosts(char *hosts_str, char **error) 189{ 190 char *hostportmech, *hpm; 191 char *hostname; 192 char *port_str; 193 char *mech_str; 194 int port; 195 int port_default = -1; 196 gss_OID mech_oid; 197 char *lasts_hpm; 198 hostlist_t *lasthost = NULL; | 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; |
|
199 hostlist_t *newhost; 200 struct hostent *hostentry; 201 int error_num; 202 int rc; 203#if DEBUG 204 char addr_buf[INET6_ADDRSTRLEN]; 205 int num_of_hosts = 0; 206#endif 207 | 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 |
208 hosts = lasthost; 209 | |
210 DPRINT((dfile, "parsing %s\n", hosts_str)); 211 while ((hostportmech = strtok_r(hosts_str, ",", &lasts_hpm)) != NULL) { 212 213 hosts_str = NULL; 214 hostname = NULL; 215 port_str = NULL; 216 port = port_default; 217 mech_str = NULL; --- 111 unchanged lines hidden (view full) --- 329 newhost->port = htons(port); 330 newhost->mech = mech_oid; 331 newhost->next_host = NULL; 332 if (lasthost != NULL) { 333 lasthost->next_host = newhost; 334 lasthost = lasthost->next_host; 335 } else { 336 lasthost = newhost; | 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; |
337 hosts = newhost; | 351 hosts_new = newhost; |
338 } 339#if DEBUG 340 num_of_hosts++; 341#endif 342 } 343 | 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; |
|
344 current_host = hosts; | 363 current_host = hosts; |
364 (void) pthread_mutex_unlock(&plugin_mutex); 365 |
|
345 DPRINT((dfile, "Configured %d hosts.\n", num_of_hosts)); 346 347 return (AUDITD_SUCCESS); 348} 349 350 | 366 DPRINT((dfile, "Configured %d hosts.\n", num_of_hosts)); 367 368 return (AUDITD_SUCCESS); 369} 370 371 |
351/* 352 * Frees host list 353 */ 354static void 355freehostlist() 356{ 357 hostlist_t *h, *n; 358 359 (void) pthread_mutex_lock(&plugin_mutex); 360 h = hosts; 361 while (h) { 362 n = h->next_host; 363 freehostent(h->host); 364 free(h); 365 h = n; 366 } 367 current_host = NULL; 368 hosts = NULL; 369 (void) pthread_mutex_unlock(&plugin_mutex); 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; | 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 } |
|
610 break; 611 case SEND_RECORD_NEXT: | 614 break; 615 case SEND_RECORD_NEXT: |
612 DPRINT((dfile, "retry the same host: %s (penalty)\n", 613 current_host->host->h_name)); | 616 DPRINT((dfile, "retry the same host: %s (penalty) " 617 "rsn:%d\n", current_host->host->h_name, err_rsn)); |
614 attempts++; 615 break; 616 case SEND_RECORD_RETRY: | 618 attempts++; 619 break; 620 case SEND_RECORD_RETRY: |
617 DPRINT((dfile, "retry the same host: %s (no penalty)\n", 618 current_host->host->h_name)); | 621 DPRINT((dfile, "retry the same host: %s (no penalty) " 622 "rsn:%d\n", current_host->host->h_name, err_rsn)); |
619 break; 620 } 621 | 623 break; 624 } 625 |
622 | |
623 if (send_record_rc == SEND_RECORD_NEXT) { 624 625 /* warn about unsuccessful auditd record delivery */ 626 rsn_msg = rsn_to_msg(err_rsn); 627 (void) asprintf(&ext_error, 628 "retry %d connection %s:%d %s", attempts + 1, 629 current_host->host->h_name, 630 ntohs(current_host->port), rsn_msg); 631 if (ext_error == NULL) { 632 free(rsn_msg); 633 *error = strdup(gettext("no memory")); 634 rc = AUDITD_NO_MEMORY; 635 break; 636 } 637 __audit_dowarn2("plugin", "audit_remote.so", "retry", 638 ext_error, attempts + 1); 639 free(rsn_msg); 640 free(ext_error); 641 | 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 |
642 | |
643 if (attempts < retries) { 644 /* semi-exponential timeout back off */ 645 timeout = BOFF_TIMEOUT(attempts, timeout); 646 DPRINT((dfile, "New timeout=%d\n", timeout)); 647 } else { 648 /* get next host */ 649 current_host = current_host->next_host; 650 if (current_host == NULL) { 651 current_host = hosts; 652 } | 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 } |
653 timeout = RST_TIMEOUT(timeout_p_timeout); | 655 timeout = timeout_p_timeout; |
654 DPRINT((dfile, "New timeout=%d\n", timeout)); 655 attempts = 0; 656 } 657 | 656 DPRINT((dfile, "New timeout=%d\n", timeout)); 657 attempts = 0; 658 } 659 |
658 | |
659 /* one cycle finished */ 660 if (current_host == start_host && attempts == 0) { 661 nosuccess_cnt++; 662 (void) asprintf(&ext_error, "all hosts defined " 663 "as p_hosts were tried to deliver " 664 "the audit record to with no success " 665 "- sleeping for %d seconds", 666 NOSUCCESS_DELAY); --- 50 unchanged lines hidden (view full) --- 717#if DEBUG 718 dfile = __auditd_debug_file_open(); 719#endif 720 721 /* initial open or audit -s */ 722 if (kvlist != NULL) { 723 DPRINT((dfile, "Action: initial open or `audit -s`\n")); 724 val_str = kva_match(kv, "p_timeout"); | 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"); |
725 if (val_str != NULL) { 726 DPRINT((dfile, "val_str=%s\n", val_str)); 727 errno = 0; 728 val = atoi(val_str); 729 if (errno == 0 && val >= 1) { 730 timeout_p_timeout = val; 731 timeout = val; 732 } | 726 if (val_str == NULL) { 727 *error = strdup( 728 gettext("p_timeout attribute not found")); 729 return (AUDITD_RETRY); |
733 } | 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 } |
|
734 735 val_str = kva_match(kv, "p_retries"); | 743 744 val_str = kva_match(kv, "p_retries"); |
736 if (val_str != NULL) { 737 DPRINT((dfile, "val_str=%s\n", val_str)); 738 errno = 0; 739 val = atoi(val_str); 740 if (errno == 0 && val >= 0) { 741 retries = val; 742 } | 745 if (val_str == NULL) { 746 *error = strdup( 747 gettext("p_retries attribute not found")); 748 return (AUDITD_RETRY); |
743 } | 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 } |
|
744 745 val_str = kva_match(kv, "qsize"); | 756 757 val_str = kva_match(kv, "qsize"); |
746 if (val_str != NULL) { 747 DPRINT((dfile, "qsize=%s\n", val_str)); 748 errno = 0; 749 val_l = atol(val_str); 750 if (errno == 0 && val_l > 0) { 751 transq_count_max = val_l; 752 } 753 754 } else { 755 DPRINT((dfile, "qsize not in kvlist\n")); 756 if ((rc = set_transq_count_max()) != AUDITD_SUCCESS) { 757 *error = strdup(gettext("cannot get kernel " 758 "auditd queue high water mark\n")); 759 return (rc); 760 } | 758 if (val_str == NULL) { 759 *error = strdup(gettext("qsize attribute not found")); 760 return (AUDITD_RETRY); |
761 } | 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 } |
|
762 DPRINT((dfile, "timeout=%d, retries=%d, transq_count_max=%ld\n", 763 timeout, retries, transq_count_max)); 764 765 val_str = kva_match(kv, "p_hosts"); 766 if (val_str == NULL) { 767 *error = strdup(gettext("no hosts configured")); 768 return (AUDITD_RETRY); 769 } --- 32 unchanged lines hidden (view full) --- 802auditd_plugin_close(char **error) 803{ 804 reset_transport(DO_EXIT, DO_SYNC); 805 if (pthread_join(recv_tid, NULL) != 0) { 806 *error = strdup(gettext("unable to close receiving thread")); 807 return (AUDITD_RETRY); 808 } 809 | 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 |
810 freehostlist(); | 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; |
811 *error = NULL; 812 return (AUDITD_SUCCESS); 813} | 827 *error = NULL; 828 return (AUDITD_SUCCESS); 829} |