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}