[PATCH 6/8][v2] audisp-racf plugin - plugin main code
by Klaus Heinrich Kiwi
This patch implements the main body for the racf plugin. It uses the
auparse_feed() interface to add a callback interface that's called
whenever a complete event is read from stdin.
The push_event() callback does the BER encoding and enqueues the encoded
event.
The 'submission_thread' then dequeues it and synchronously submits it to
the RACF server (using the ldap interface).
SIGHUP re-reads the configuration file and forces a LDAP interface
reinitialization (forcing network connection flush). The submission
thread is stopped and restarted to avoid messing with the queue in an
invalid state. The queue is not touched between SIGHUPS.
Signed-off-by: Klaus Heinrich Kiwi <klausk(a)br.ibm.com>
diff -purN audit-1.6.2/audisp/plugins/racf/racf-plugin.c audit-1.6.2_racf/audisp/plugins/racf/racf-plugin.c
--- audit-1.6.2/audisp/plugins/racf/racf-plugin.c 1969-12-31 21:00:00.000000000 -0300
+++ audit-1.6.2_racf/audisp/plugins/racf/racf-plugin.c 2007-10-10 10:26:18.000000000 -0300
@@ -0,0 +1,558 @@
+/***************************************************************************
+* Copyright (C) 2007 International Business Machines Corp. *
+* All Rights Reserved. *
+* *
+* This program is free software; you can redistribute it and/or modify *
+* it under the terms of the GNU General Public License as published by *
+* the Free Software Foundation; either version 2 of the License, or *
+* (at your option) any later version. *
+* *
+* This program is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU General Public License for more details. *
+* *
+* You should have received a copy of the GNU General Public License *
+* along with this program; if not, write to the *
+* Free Software Foundation, Inc., *
+* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+* *
+* Authors: *
+* Klaus Heinrich Kiwi <klausk(a)br.ibm.com> *
+***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <limits.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <string.h>
+#include <pthread.h>
+#include <lber.h>
+#include <netinet/in.h>
+#include "auparse.h"
+#include "racf-log.h"
+#include "racf-ldap.h"
+#include "racf-config.h"
+#include "racf-queue.h"
+
+/*
+ * Global vars
+ */
+volatile int stop = 0;
+volatile int hup = 0;
+volatile RACF racf_inst;
+static racf_conf_t conf;
+static const char *def_config_file = "/etc/audisp/racf.conf";
+static pthread_t submission_thread;
+pid_t mypid = 0;
+
+/*
+ * SIGTERM handler
+ */
+static void term_handler(int sig)
+{
+ log_info("Got SIGTERM - Exiting");
+ stop = 1;
+ nudge_queue();
+}
+
+/*
+ * SIGHUP handler - re-read config, reconnect to RACF
+ */
+static void hup_handler(int sig)
+{
+ log_info("Got SIGHUP - flushing configuration");
+ hup = 1;
+ nudge_queue();
+}
+
+/*
+ * SIGALRM handler - help force exit when terminating daemon
+ */
+static void alarm_handler(int sig)
+{
+ log_err("Aborting submission thread");
+ pthread_cancel(submission_thread);
+}
+
+/*
+ * The submission thread
+ * It's job is to dequeue the events from the queue
+ * and sync submit them to RACF
+ */
+static void *submission_thread_main(void *arg)
+{
+ int rc;
+
+ log_debug("Starting event submission thread");
+
+ rc = racf_init(&racf_inst, conf.server,
+ conf.port, conf.user,
+ conf.password,
+ conf.timeout);
+
+ if (rc != ICTX_SUCCESS) {
+ log_err("Error - RACF instance initialization failed");
+ stop = 1;
+ return 0;
+ }
+
+ while (stop == 0) {
+ /* block until we have an event */
+ BerElement *ber = dequeue();
+
+ if (ber == NULL) {
+ if (hup) {
+ break;
+ }
+ continue;
+ }
+ debug_ber(ber);
+ rc = submit_request_s(&racf_inst, ber);
+ if (rc == ICTX_E_FATAL) {
+ log_err("Error - Fatal error in event submission");
+ stop = 1;
+ } else if (rc != ICTX_SUCCESS) {
+ log_err("Event submission failure - event dropped");
+ }
+ else {
+ log_debug("Event submission success");
+ }
+ ber_free(ber, 1); /* also free BER buffer */
+ }
+ log_debug("Stopping event submission thread");
+ racf_destroy(&racf_inst);
+
+ return 0;
+}
+
+
+/*
+ * auparse library callback that's called when an event is ready
+ */
+void
+push_event(auparse_state_t * au, auparse_cb_event_t cb_event_type,
+ void *user_data)
+{
+ int rc;
+ BerElement *ber;
+ int qualifier;
+ char timestamp[26];
+ char linkValue[RACF_LINK_VALUE_SIZE];
+ char logString[RACF_LOGSTRING_SIZE];
+ unsigned long linkValue_tmp;
+
+ if (cb_event_type != AUPARSE_CB_EVENT_READY)
+ return;
+
+ const au_event_t *e = auparse_get_timestamp(au);
+ if (e == NULL)
+ return;
+ /*
+ * we have an event. Each record will result in a different 'Item'
+ * (refer ASN.1 definition in racf-ldap.h)
+ */
+
+ /*
+ * Create a new BER element to encode the request
+ */
+ ber = ber_alloc_t(LBER_USE_DER);
+ if (ber == NULL) {
+ log_err("Error allocating memory for BER element");
+ goto fatal;
+ }
+
+ /*
+ * Collect some information to fill in every item
+ */
+ const char *node = auparse_get_node(au);
+ const char *orig_type = auparse_find_field(au, "type");
+ /* roll back event to get 'success' */
+ auparse_first_record(au);
+ const char *success = auparse_find_field(au, "success");
+ /* roll back event to get 'res' */
+ auparse_first_record(au);
+ const char *res = auparse_find_field(au, "res");
+
+ /* check if this event is a success or failure one */
+ if (success) {
+ if (strncmp(success, "0", 1) == 0 ||
+ strncmp(success, "no", 2) == 0)
+ qualifier = RACF_QUALIF_FAIL;
+ else
+ qualifier = RACF_QUALIF_SUCCESS;
+ } else if (res) {
+ if (strncmp(res, "0", 1) == 0
+ || strncmp(res, "failed", 6) == 0)
+ qualifier = RACF_QUALIF_FAIL;
+ else
+ qualifier = RACF_QUALIF_SUCCESS;
+ } else
+ qualifier = RACF_QUALIF_INFO;
+
+ /* get timestamp text */
+ ctime_r(&e->sec, timestamp);
+ timestamp[24] = '\0'; /* strip \n' */
+
+ /* prepare linkValue which will be used for every item */
+ linkValue_tmp = htonl(e->serial); /* padronize to use network
+ * byte order
+ */
+ memset(&linkValue, 0, RACF_LINK_VALUE_SIZE);
+ memcpy(&linkValue, &linkValue_tmp, sizeof(unsigned long));
+
+ /*
+ * Prepare the logString with some meaningful text
+ * We assume the first record type found is the
+ * 'originating' audit record
+ */
+ sprintf(logString, "Linux (%s): type: %s", node, orig_type);
+
+ /*
+ * Start writing to BER element.
+ * There's only one field (version) out of the item sequence.
+ * Also open item sequence
+ */
+ rc = ber_printf(ber, "{i{", ICTX_REQUESTVER);
+ if (rc < 0)
+ goto skip_event;
+
+ /*
+ * Roll back to first record and iterate through all records
+ */
+ auparse_first_record(au);
+ do {
+ const char *type = auparse_find_field(au, "type");
+ if (type == NULL)
+ goto skip_event;
+
+ log_debug("got record: %s", auparse_get_record_text(au));
+
+ /*
+ * First field is item Version, same as global version
+ */
+ rc = ber_printf(ber, "{i", ICTX_REQUESTVER);
+
+ /*
+ * Second field is the itemTag
+ * use our internal event counter, increasing it
+ */
+ rc |= ber_printf(ber, "i", conf.counter++);
+
+ /*
+ * Third field is the linkValue
+ * using ber_put_ostring since it is not null-terminated
+ */
+ rc |= ber_put_ostring(ber, linkValue,
+ RACF_LINK_VALUE_SIZE,
+ LBER_OCTETSTRING);
+ /*
+ * Fourth field is the violation
+ * Don't have anything better yet to put here
+ */
+ rc |= ber_printf(ber, "b", 0);
+
+ /*
+ * Fifth field is the event.
+ * FIXME: this might be the place to switch on the
+ * audit record type and map to a more meaningful
+ * RACF event here
+ */
+ rc |= ber_printf(ber, "i", RACF_EVENT_AUTHORIZATION);
+
+ /*
+ * Sixth field is the qualifier. We map 'success' or
+ * 'res' to this field
+ */
+ rc |= ber_printf(ber, "i", qualifier);
+
+ /*
+ * Seventh field is the Class
+ * always use '@LINUX' for this version
+ * max size RACF_CLASS_SIZE
+ */
+ rc |= ber_printf(ber, "t", ASN1_IA5STRING_TAG);
+ rc |= ber_printf(ber, "s", "@LINUX");
+
+ /*
+ * Eighth field is the resource
+ * use the record type (name) as the resource
+ * max size RACF_RESOURCE_SIZE
+ */
+ rc |= ber_printf(ber, "t", ASN1_IA5STRING_TAG);
+ rc |= ber_printf(ber, "s", type);
+
+ /*
+ * Nineth field is the LogString
+ * we try to put something meaningful here
+ * we also start the relocations sequence
+ */
+ rc |= ber_printf(ber, "t", ASN1_IA5STRING_TAG);
+ rc |= ber_printf(ber, "s{", logString);
+
+ /*
+ * Now we start adding the relocations.
+ * Let's add the timestamp as the first one
+ * so it's out of the field loop
+ */
+ rc |= ber_printf(ber, "{i", RACF_RELOC_TIMESTAMP);
+ rc |= ber_printf(ber, "t", ASN1_IA5STRING_TAG);
+ rc |= ber_printf(ber, "s}", timestamp);
+
+ /*
+ * Check that encoding is going OK until now
+ */
+ if (rc < 0)
+ goto skip_event;
+
+ /*
+ * Now go to first field,
+ * and iterate through all fields
+ */
+ auparse_first_field(au);
+ do {
+ /*
+ * we set a maximum of 1024 chars for
+ * relocation data (field=value pairs)
+ * Hopefuly this wont overflow too often
+ */
+ char data[1024];
+ const char *name = auparse_get_field_name(au);
+ const char *value = auparse_get_field_str(au);
+ if (name == NULL || value == NULL)
+ goto skip_event;
+
+ /*
+ * First reloc field is the Relocation type
+ * We use 'OTHER' here since we don't have
+ * anything better
+ */
+ rc |= ber_printf(ber, "{i", RACF_RELOC_OTHER);
+
+ /*
+ * Second field is the relocation data
+ * We use a 'name=value' pair here
+ * Use up to 1023 chars (one char left for '\0')
+ */
+ snprintf(data, 1023, "%s=%s", name, value);
+ rc |= ber_printf(ber, "t", ASN1_IA5STRING_TAG);
+ rc |= ber_printf(ber, "s}", data);
+
+ /*
+ * Check encoding status
+ */
+ if (rc < 0)
+ goto skip_event;
+ } while (auparse_next_field(au) > 0);
+
+ /*
+ * After adding all relocations we are done with
+ * this item - finalize relocs and item
+ */
+ rc |= ber_printf(ber, "}}");
+
+ /*
+ * Check if we are doing well with encoding
+ */
+ if (rc < 0)
+ goto skip_event;
+
+ } while (auparse_next_record(au) > 0);
+
+ /*
+ * We have all items in - finalize item sequence & request
+ */
+ rc |= ber_printf(ber, "}}");
+
+ /*
+ * Check if everything went alright with encoding
+ */
+ if (rc < 0)
+ goto skip_event;
+
+ /*
+ * finally, enqueue request and let the other
+ * thread process it
+ */
+ log_debug("Encoding done, enqueuing event");
+ enqueue(ber);
+
+ return;
+
+skip_event:
+ log_warn("Warning - error encoding request, skipping event");
+ ber_free(ber, 1); /* free it since we're not enqueuing it */
+ return;
+
+fatal:
+ log_err("Fatal error while encoding request - aborting");
+ stop = 1;
+}
+
+int main(int argc, char *argv[])
+{
+ int rc;
+ char *cpath;
+ char buf[1024];
+ struct sigaction sa;
+ sigset_t ss;
+ auparse_state_t *au;
+ ssize_t len;
+
+ mypid = getpid();
+
+ log_info("starting");
+
+ /*
+ * install signal handlers
+ */
+ sa.sa_flags = 0;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_handler = term_handler;
+ sigaction(SIGTERM, &sa, NULL);
+ sa.sa_handler = hup_handler;
+ sigaction(SIGHUP, &sa, NULL);
+ sa.sa_handler = alarm_handler;
+ sigaction(SIGALRM, &sa, NULL);
+
+ /*
+ * the main program accepts a single (optional) argument:
+ * it's configuration file (this is NOT the plugin configuration
+ * usually located at /etc/audisp/plugin.d)
+ * We use the default (def_config_file) if no arguments are given
+ */
+ if (argc == 1) {
+ cpath = def_config_file;
+ log_warn("No configuration file specified - using default (%s)", cpath);
+ } else if (argc == 2) {
+ cpath = argv[1];
+ log_info("Configuration file: %s", cpath);
+ } else {
+ log_err("Error - invalid number of parameters");
+ return 1;
+ }
+
+ /* initialize record counter */
+ conf.counter = 1;
+
+ /* initialize configuration with default values */
+ racf_clear_config(&conf);
+
+ /* initialize the submission queue */
+ if (init_queue(conf.q_depth) != 0) {
+ log_err("Error - Can't initialize event queue");
+ return -1;
+ }
+ /* set stdin to O_NONBLOCK */
+ if (fcntl(0, F_SETFL, O_NONBLOCK) == -1) {
+ log_err("Error - Can't set input to Non-blocking mode: %s",
+ strerror(errno));
+ return -1;
+ }
+
+ do {
+
+ hup = 0; /* don't flush unless hup == 1 */
+
+ /*
+ * initialization is done in 4 steps:
+ */
+
+ /*
+ * load configuration and
+ * increase queue depth if needed
+ */
+ rc = racf_load_config(&conf, cpath);
+ if (rc != 0) {
+ log_err("Error - Can't load configuration");
+ return -1;
+ }
+ increase_queue_depth(conf.q_depth); /* 1 */
+
+ /* initialize auparse */
+ au = auparse_init(AUSOURCE_FEED, 0); /* 2 */
+
+ /*
+ * Block signals for everyone,
+ * Initialize submission thread, and
+ * Unblock signals for this thread
+ */
+ sigfillset(&ss);
+ pthread_sigmask(SIG_BLOCK, &ss, NULL);
+ pthread_create(&submission_thread, NULL,
+ submission_thread_main, NULL);
+ pthread_sigmask(SIG_UNBLOCK, &ss, NULL); /* 3 */
+
+ /* add our event consumer callback */
+ auparse_add_callback(au, push_event, NULL, NULL); /* 4 */
+
+ /* main loop */
+ while (hup == 0 && stop == 0) {
+ fd_set rfds;
+ struct timeval tv;
+
+ FD_ZERO(&rfds);
+ FD_SET(0, &rfds);
+ tv.tv_sec = 5;
+ tv.tv_usec = 0;
+ rc = select(1, &rfds, NULL, NULL, &tv);
+ if (rc == -1) {
+ if (errno == EINTR) {
+ log_debug("Select call interrupted");
+ continue;
+ }
+ else {
+ log_err("Error with select: %s",
+ strerror(errno));
+ stop = 1;
+ }
+ }
+ else if (rc) {
+ len = read(0, buf, 1024);
+ if (len > 0)
+ /* let our callback know of the new data */
+ auparse_feed(au, buf, len);
+ else if (len == 0) {
+ log_debug("End of input - Exiting");
+ stop = 1;
+ }
+ else {
+ /* ignore interrupted call or empty pipe */
+ if (errno != EINTR && errno != EAGAIN) {
+ log_err("Error reading from input: %s",
+ strerror(errno));
+ stop = 1;
+ }
+ else {
+ log_debug("Ignoring read failure: %s",
+ strerror(errno));
+ }
+ }
+ }
+ }
+ /* flush everything, in order */
+ auparse_flush_feed(au); /* 4 */
+ alarm(10); /* 10 seconds to clear the queue */
+ pthread_join(submission_thread, NULL); /* 3 */
+ alarm(0); /* cancel any pending alarm */
+ auparse_destroy(au); /* 2 */
+ racf_free_config(&conf); /* 1 */
+ }
+ while (hup && stop == 0);
+
+ /* destroy queue before leaving */
+ destroy_queue();
+
+ log_debug("Exiting");
+
+ return 0;
+}
17 years, 2 months
[PATCH 5/8][v2] audisp-racf plugin - queue interface
by Klaus Heinrich Kiwi
This patch implements a queue for already-encoded BER elements for the
racf plugin.
This is entirely based on audit dispatcher code by Steve Grubb.
Signed-off-by: Klaus Heinrich Kiwi <klausk(a)br.ibm.com>
diff -purN audit-1.6.2/audisp/plugins/racf/racf-queue.c audit-1.6.2_racf/audisp/plugins/racf/racf-queue.c
--- audit-1.6.2/audisp/plugins/racf/racf-queue.c 1969-12-31 21:00:00.000000000 -0300
+++ audit-1.6.2_racf/audisp/plugins/racf/racf-queue.c 2007-10-10 10:26:18.000000000 -0300
@@ -0,0 +1,144 @@
+/***************************************************************************
+ * Copyright (C) 2007 International Business Machines Corp. *
+ * All Rights Reserved. *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ * *
+ * Authors: *
+ * Klaus Heinrich Kiwi <klausk(a)br.ibm.com> *
+ * based on code by Steve Grubb <sgrubb(a)redhat.com> *
+ ***************************************************************************/
+
+#include "racf-queue.h"
+
+#include <stdlib.h>
+#include <pthread.h>
+#include <syslog.h>
+#include "racf-log.h"
+
+static volatile BerElement **q;
+static pthread_mutex_t queue_lock;
+static pthread_cond_t queue_nonempty;
+static unsigned int q_next, q_last, q_depth;
+
+
+int init_queue(unsigned int size)
+{
+ unsigned int i;
+
+ q_next = 0;
+ q_last = 0;
+ q_depth = size;
+ q = malloc(q_depth * sizeof(BerElement *));
+ if (q == NULL)
+ return -1;
+
+ for (i=0; i<q_depth; i++)
+ q[i] = NULL;
+
+ /* Setup IPC mechanisms */
+ pthread_mutex_init(&queue_lock, NULL);
+ pthread_cond_init(&queue_nonempty, NULL);
+
+ return 0;
+}
+
+void enqueue(BerElement *ber)
+{
+ unsigned int n, retry_cnt = 0;
+
+retry:
+ /* We allow 3 retries and then its over */
+ if (retry_cnt > 3) {
+ log_err("queue is full - dropping event");
+ return;
+ }
+ pthread_mutex_lock(&queue_lock);
+
+ /* OK, have lock add event */
+ n = q_next%q_depth;
+ if (q[n] == NULL) {
+ q[n] = ber;
+ q_next = (n+1) % q_depth;
+ pthread_cond_signal(&queue_nonempty);
+ pthread_mutex_unlock(&queue_lock);
+ } else {
+ pthread_mutex_unlock(&queue_lock);
+ pthread_yield(); /* Let dequeue thread run to clear queue */
+ retry_cnt++;
+ goto retry;
+ }
+}
+
+BerElement *dequeue(void)
+{
+ BerElement *ber;
+ unsigned int n;
+
+ /* Wait until its got something in it */
+ pthread_mutex_lock(&queue_lock);
+ n = q_last%q_depth;
+ if (q[n] == NULL) {
+ pthread_cond_wait(&queue_nonempty, &queue_lock);
+ n = q_last%q_depth;
+ }
+
+ /* OK, grab the next event */
+ if (q[n] != NULL) {
+ ber = (BerElement *) q[n];
+ q[n] = NULL;
+ q_last = (n+1) % q_depth;
+ } else
+ ber = NULL;
+
+ pthread_mutex_unlock(&queue_lock);
+
+ /* Process the event */
+ return ber;
+}
+
+void nudge_queue(void)
+{
+ pthread_cond_signal(&queue_nonempty);
+}
+
+void increase_queue_depth(unsigned int size)
+{
+ pthread_mutex_lock(&queue_lock);
+ if (size > q_depth) {
+ unsigned int i;
+ void *tmp_q;
+
+ tmp_q = realloc(q, size * sizeof(BerElement *));
+ q = tmp_q;
+ for (i=q_depth; i<size; i++)
+ q[i] = NULL;
+ q_depth = size;
+ }
+ pthread_mutex_unlock(&queue_lock);
+}
+
+void destroy_queue(void)
+{
+ unsigned int i;
+
+ for (i=0; i<q_depth; i++) {
+ ber_free(q[i], 1);
+ }
+
+ free(q);
+}
+
diff -purN audit-1.6.2/audisp/plugins/racf/racf-queue.h audit-1.6.2_racf/audisp/plugins/racf/racf-queue.h
--- audit-1.6.2/audisp/plugins/racf/racf-queue.h 1969-12-31 21:00:00.000000000 -0300
+++ audit-1.6.2_racf/audisp/plugins/racf/racf-queue.h 2007-10-10 10:26:18.000000000 -0300
@@ -0,0 +1,38 @@
+/***************************************************************************
+ * Copyright (C) 2007 International Business Machines Corp. *
+ * All Rights Reserved. *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ * *
+ * Authors: *
+ * Klaus Heinrich Kiwi <klausk(a)br.ibm.com> *
+ * based on code by Steve Grubb <sgrubb(a)redhat.com> *
+ ***************************************************************************/
+
+#ifndef _RACF_QUEUE_H
+#define _RACF_QUEUE_H
+
+#include <lber.h>
+
+int init_queue(unsigned int size);
+void enqueue(BerElement *);
+BerElement *dequeue(void);
+void nudge_queue(void);
+void increase_queue_depth(unsigned int size);
+void destroy_queue(void);
+
+#endif /* _RACF_QUEUE_H */
+
17 years, 2 months
[PATCH 4/8][v2] audisp-racf plugin - logging interface
by Klaus Heinrich Kiwi
This patch implements a simple logging interface for the racf plugin.
There's also some debugging code that's completely disabled if 'DEBUG'
symbol isn't defined.
Messages are logged to the syslog (DAEMON facility) with info, warn and
err priorities.
Signed-off-by: Klaus Heinrich Kiwi <klausk(a)br.ibm.com>
diff -purN audit-1.6.2/audisp/plugins/racf/racf-log.c audit-1.6.2_racf/audisp/plugins/racf/racf-log.c
--- audit-1.6.2/audisp/plugins/racf/racf-log.c 1969-12-31 21:00:00.000000000 -0300
+++ audit-1.6.2_racf/audisp/plugins/racf/racf-log.c 2007-10-10 10:26:18.000000000 -0300
@@ -0,0 +1,109 @@
+/***************************************************************************
+ * Copyright (C) 2007 International Business Machines Corp. *
+ * All Rights Reserved. *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ * *
+ * Authors: *
+ * Klaus Heinrich Kiwi <klausk(a)br.ibm.com> *
+ ***************************************************************************/
+#include "racf-log.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "auparse.h"
+
+
+static void vlog_prio(int prio, const char *fmt, va_list ap)
+{
+ char *str;
+
+ if (asprintf(&str, "pid=%d: %s", mypid, fmt) != -1) {
+ vsyslog(LOG_DAEMON | prio, str, ap);
+ free(str);
+ }
+}
+
+void log_err(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vlog_prio(LOG_ERR, fmt, ap);
+ va_end(ap);
+}
+
+void log_warn(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vlog_prio(LOG_WARNING, fmt, ap);
+ va_end(ap);
+}
+
+void log_info(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vlog_prio(LOG_INFO, fmt, ap);
+ va_end(ap);
+}
+
+void _log_debug(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vlog_prio(LOG_INFO, fmt, ap);
+ va_end(ap);
+}
+
+void _debug_ber(BerElement * ber)
+{
+ struct berval bv;
+
+ if (ber_flatten2(ber, &bv, 0) != -1) {
+ debug_bv(&bv);
+ }
+}
+
+void _debug_bv(struct berval *bv)
+{
+ char *out;
+ char octet[4];
+ ber_len_t i;
+
+ log_debug("---BER value HEX dump (size %u bytes)",
+ (unsigned int) bv->bv_len);
+
+ if (bv->bv_len > 0) {
+ out = (char *) calloc((3 * (bv->bv_len)) + 1, sizeof(char));
+ if (!out) return;
+
+ for (i = 1; i <= bv->bv_len; i++) {
+ snprintf(octet, 4, "%02x ",
+ (unsigned char) bv->bv_val[i - 1]);
+ strcat(out, octet);
+ }
+ log_debug(out);
+ free(out);
+ }
+}
+
+
diff -purN audit-1.6.2/audisp/plugins/racf/racf-log.h audit-1.6.2_racf/audisp/plugins/racf/racf-log.h
--- audit-1.6.2/audisp/plugins/racf/racf-log.h 1969-12-31 21:00:00.000000000 -0300
+++ audit-1.6.2_racf/audisp/plugins/racf/racf-log.h 2007-10-10 10:26:18.000000000 -0300
@@ -0,0 +1,58 @@
+/***************************************************************************
+ * Copyright (C) 2007 International Business Machines Corp. *
+ * All Rights Reserved. *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ * *
+ * Authors: *
+ * Klaus Heinrich Kiwi <klausk(a)br.ibm.com> *
+ ***************************************************************************/
+
+#ifndef _RACF_LOG_H
+#define _RACF_LOG_H
+
+#include "racf-ldap.h"
+
+#include <syslog.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <lber.h>
+
+extern pid_t mypid;
+
+void log_err(const char *, ...);
+void log_warn(const char *, ...);
+void log_info(const char *, ...);
+void _log_debug(const char *, ...);
+void _debug_bv(struct berval *);
+void _debug_ber(BerElement *);
+
+#ifdef DEBUG
+
+#define log_debug(fmt, ...) _log_debug(fmt, ## __VA_ARGS__)
+#define debug_bv(bv) _debug_bv(bv)
+#define debug_ber(ber) _debug_ber(ber)
+
+#else
+
+#define log_debug(fmt, ...)
+#define debug_bv(bv)
+#define debug_ber(ber)
+
+#endif /* DEBUG */
+
+
+#endif /* _RACF_LOG_H */
17 years, 2 months
[PATCH 3/8][v2] audisp-racf plugin - ITDS LDAP interface
by Klaus Heinrich Kiwi
This patch brings the LDAP interface for the racf plugin. Functions here
aim to initialize (read as: take necessary arguments), connect and
submit the LDAP extended operation to the RACF server. There's also code
to get the RACF server response, filling an internally-defined struct
that is then checked for errors.
The connection itself can be reestablished if the plugin thinks it timed
out, after trying to submit the event directly. In case of event bursts,
this prevents the plugin of trying a connection upon every event
arrival, avoiding at the same time a synchronous keepalive operation.
Signed-off-by: Klaus Heinrich Kiwi <klausk(a)br.ibm.com>
diff -purN audit-1.6.2/audisp/plugins/racf/racf-ldap.c audit-1.6.2_racf/audisp/plugins/racf/racf-ldap.c
--- audit-1.6.2/audisp/plugins/racf/racf-ldap.c 1969-12-31 21:00:00.000000000 -0300
+++ audit-1.6.2_racf/audisp/plugins/racf/racf-ldap.c 2007-10-10 10:26:18.000000000 -0300
@@ -0,0 +1,608 @@
+/***************************************************************************
+ * Copyright (C) 2007 International Business Machines Corp. *
+ * All Rights Reserved. *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ * *
+ * Authors: *
+ * Klaus Heinrich Kiwi <klausk(a)br.ibm.com> *
+ ***************************************************************************/
+
+#include "racf-ldap.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "racf-log.h"
+
+/***************************************************************************
+ * Audit response struct *
+ ***************************************************************************/
+typedef struct audit_resp_item
+{
+ ber_int_t version; /* Version of Response data itself */
+ ber_int_t itemTag; /* Copy of itemTag from Operation */
+ ber_int_t majorCode; /* Majorcode. Main return code of this Outcome */
+ ber_int_t minorCode1; /* minorCode1. SAFRc or other Rc */
+ ber_int_t minorCode2; /* minorCode2. RacfRc or other Rc */
+ ber_int_t minorCode3; /* minorCode3. racfRsn or other Rc */
+} audit_resp_item_t;
+
+typedef struct audit_response
+{
+ ber_int_t respVersion; /* Overall version */
+ ber_int_t respMajor; /* Overall major code */
+ unsigned int numItems; /* Number of response items */
+ audit_resp_item_t **itemList; /* response ItemList */
+} audit_response_t;
+
+
+/***************************************************************************
+ * RACF Major return code handling *
+ ***************************************************************************/
+struct racf_error
+{
+ int code;
+ char *str;
+};
+
+static struct racf_error racf_errlist[] = {
+ {RACF_MAJOR_SUCCESS, "Success"},
+ {RACF_MAJOR_WARNINGMODE, "WARNINGMODE - Event was logged, with warnings"},
+ {RACF_MAJOR_NOTREQ, "NOTREQ - No logging required"},
+ {RACF_MAJOR_UNDETERMINED, "UNDETERMINED - Undetermined result"},
+ {RACF_MAJOR_UNAUTHORIZED, "UNAUTHORIZED - The user does not have authority the R_auditx service"},
+ {RACF_MAJOR_RACROUTE, "RACROUTE - The R_auditx service returned an unexpected error"},
+ {RACF_MAJOR_VAL_ERR, "VAL_ERR - Value error in request"},
+ {RACF_MAJOR_ENC_ERR, "ENC_ERR - DER decoding error in request"},
+ {RACF_MAJOR_UNSUF_AUTH, "UNSUF_AUTH - The user has unsuficient authority for the requested function"},
+ {RACF_MAJOR_EMPTY, "EMPTY - Empty request received - No items found within the ItemList"},
+ {RACF_MAJOR_INVALID_VER, "INVALID_VER - Invalid RequestVersion"},
+ {RACF_MAJOR_INTERNAL_ERR, "INTERNAL_ERR - An internal error was encountered within the ICTX component"},
+ {-1, NULL}
+};
+
+/***************************************************************************
+ * Internal functions prototypes *
+ ***************************************************************************/
+static int _racf_init(RACF *);
+static void _racf_destroy(RACF *);
+static int racf_connect(RACF *);
+static void racf_disconnect(RACF *);
+static int submit_xop_s(RACF *, struct berval *);
+static int decode_response(audit_response_t *, struct berval *);
+
+/***************************************************************************
+ * Exported functions *
+ ***************************************************************************/
+int submit_request_s(RACF *racf, BerElement *ber)
+{
+ int rc, retry = 1; /* retry once and give up */
+ struct berval bv;
+
+ rc = ber_flatten2(ber, &bv, 0); /* 0 = Use ber's buffer */
+ if (rc == -1) {
+ log_err("Error flattening BER element");
+ return ICTX_E_ABORT;
+ }
+
+retry:
+ rc = submit_xop_s(racf, &bv);
+ switch (rc) {
+ case ICTX_SUCCESS:
+ break;
+ case ICTX_E_TRYAGAIN:
+ /*
+ * Usually means that the server connection timed-out
+ * So we flush the LDAP connection by unsetting the
+ * 'connected' flag and trying again.
+ */
+ if (retry > 0) {
+ log_debug("Connection seems down - retrying");
+ retry--;
+ _racf_destroy(racf);
+ rc = _racf_init(racf);
+ if (rc != ICTX_SUCCESS)
+ log_err("Error - failed to re-initialize LDAP session");
+ else
+ goto retry; /* go to submit_xop_s once more */
+ }
+ log_err("Can't establish connection");
+ break;
+ case ICTX_E_ABORT:
+ break;
+ default:
+ log_err("Event resulted failure, code: 0x%x", rc);
+ }
+
+ return rc;
+}
+
+int racf_init(RACF *racf, char *server, int port,
+ char *user, char *password, int timeout)
+{
+ racf->server = strdup(server);
+ racf->port = port;
+ racf->user = strdup(user);
+ racf->password = strdup(password);
+ racf->timeout = timeout;
+ racf->connected = 0;
+
+ if (!racf->server || !racf->user || !racf->password) {
+ log_err("Error allocating memory for RACF session members");
+ return ICTX_E_FATAL;
+ }
+
+ return _racf_init(racf);
+}
+
+void racf_destroy(RACF *racf)
+{
+ _racf_destroy(racf);
+
+ free(racf->server);
+ free(racf->user);
+ free(racf->password);
+}
+
+char *racf_err2string(int err)
+{
+ int i;
+
+ for (i = 0; racf_errlist[i].str != NULL; i++) {
+ if (err == racf_errlist[i].code)
+ return racf_errlist[i].str;
+ }
+ return "Unknown error";
+}
+
+/***************************************************************************
+ * Internal Functions *
+ ***************************************************************************/
+static int _racf_init(RACF *racf)
+{
+ int version, rc;
+ char *uri = NULL;
+
+#ifdef LDAP_DEPRECATED
+
+ log_debug("Initializing RACF LDAP connection at ldap://%s:%d",
+ racf->server, racf->port);
+ racf->ld = ldap_init(racf->server
+ racf->port ? racf->port : LDAP_PORT);
+ if (racf->ld == NULL) {
+ log_err("Error initializing LDAP session: %s",
+ strerror(errno));
+ rc = ICTX_E_FATAL;
+ goto end;
+ }
+#else
+ /* build ldap URI */
+ if (racf->port == 0 || racf->port == LDAP_PORT)
+ rc = asprintf(&uri, "ldap://%s", racf->server);
+ else
+ rc = asprintf(&uri, "ldap://%s:%d", racf->server,
+ racf->port);
+
+ if (rc == -1) {
+ log_err("Out of memory building LDAP server URI");
+ rc = ICTX_E_FATAL;
+ uri = NULL;
+ goto end;
+ }
+
+ log_debug("Initializing RACF LDAP connection at %s", uri);
+ /* Get a handle to an LDAP connection */
+ rc = ldap_initialize(&racf->ld, uri);
+ if (rc != LDAP_SUCCESS) {
+ log_err("Error initializing LDAP session: %s",
+ ldap_err2string(rc));
+ rc = ICTX_E_FATAL;
+ goto free_uri;
+ }
+#endif
+
+ /*
+ * Ensure the LDAP protocol version supported by the client
+ * to 3. (Extended operations are part of version 3).
+ */
+ rc = ldap_get_option(racf->ld, LDAP_OPT_PROTOCOL_VERSION,
+ &version);
+ if (rc != LDAP_OPT_SUCCESS) {
+ log_err("Error getting LDAP session options");
+ rc = ICTX_E_FATAL;
+ goto unbind;
+ }
+
+ if (version < LDAP_VERSION3) {
+ log_debug("Setting LDAP session version to %d",
+ LDAP_VERSION3);
+ version = LDAP_VERSION3;
+ rc = ldap_set_option(racf->ld, LDAP_OPT_PROTOCOL_VERSION,
+ &version);
+ if (rc != LDAP_OPT_SUCCESS) {
+ log_err("Error setting LDAP session version");
+ rc = ICTX_E_FATAL;
+ goto unbind;
+ }
+ }
+
+ goto free_uri;
+
+unbind:
+ ldap_unbind_ext_s(racf->ld, NULL, NULL);
+ racf->ld = NULL;
+
+free_uri:
+ free(uri);
+
+end:
+ return rc;
+}
+
+static void _racf_destroy(RACF *racf)
+{
+ racf_disconnect(racf);
+ racf->ld = NULL;
+}
+
+static int racf_connect(RACF *racf)
+{
+ struct berval cred;
+ int rc;
+ char bindusr[255];
+
+ snprintf(bindusr, 255, "racfid=%s,cn=ictx", racf->user);
+
+ log_debug("Attempting BIND. User '%s', password '<not shown>'",
+ bindusr);
+
+ cred.bv_val = (char *) racf->password;
+ cred.bv_len = strlen(racf->password);
+
+ rc = ldap_sasl_bind_s(racf->ld, bindusr,
+ LDAP_SASL_SIMPLE, &cred,
+ NULL, NULL, NULL);
+
+
+ switch (rc) {
+ case LDAP_SUCCESS:
+ log_debug("LDAP BIND succeeded");
+ racf->connected = 1;
+ rc = ICTX_SUCCESS;
+ break;
+ case LDAP_SERVER_DOWN:
+ case LDAP_BUSY:
+ case LDAP_UNAVAILABLE:
+ case LDAP_TIMEOUT:
+ case LDAP_CONNECT_ERROR:
+ log_warn("RACF connection failed: %s",
+ ldap_err2string(rc));
+ rc = ICTX_E_TRYAGAIN;
+ break;
+ default:
+ log_err("Error - RACF initialization failed: %s",
+ ldap_err2string(rc));
+ rc = ICTX_E_FATAL;
+ }
+
+ return rc;
+}
+
+
+static void racf_disconnect(RACF *racf)
+{
+ if (racf->ld) {
+ log_debug("Unbinding LDAP session");
+
+#ifdef LDAP_DEPRECATED
+ ldap_unbind(racf->ld);
+#else
+ ldap_unbind_ext_s(racf->ld, NULL, NULL);
+#endif
+ }
+ racf->connected = 0;
+
+}
+
+/*
+ * Sync-submit extended operation given in *bv
+ * return ICTX_SUCCESS if submission (and response)
+ * succeeded.
+ * Log errors using log_err() functions
+ */
+int submit_xop_s(RACF *racf, struct berval *bv)
+{
+ LDAPMessage *result;
+ audit_response_t response;
+ int rc, errcode, msgId;
+ unsigned int i;
+ char *errmsg, *oid;
+ struct berval *bv_response;
+ struct timeval t;
+
+ if (racf->connected == 0) {
+ rc = racf_connect(racf);
+ if (rc != ICTX_SUCCESS)
+ return rc;
+ }
+
+ /* call LDAP - won't block */
+ rc = ldap_extended_operation(racf->ld, ICTX_OIDAUDITREQUEST,
+ bv, NULL, NULL, &msgId);
+ if (rc == LDAP_SERVER_DOWN) {
+ racf->connected = 0;
+ return ICTX_E_TRYAGAIN;
+ } else if (rc != LDAP_SUCCESS) {
+ log_err("LDAP extended operation submission failure: %s",
+ ldap_err2string(rc));
+ return ICTX_E_ABORT;
+ } else
+ log_debug("Sent LDAP extended operation request, msgId=0x%x",
+ msgId);
+
+
+ /* call blocking ldap_result with specified timeout */
+ t.tv_sec = racf->timeout;
+ t.tv_usec = 0;
+ rc = ldap_result(racf->ld, msgId, 1, &t, &result);
+
+ if (rc == -1) {
+ /* error in ldap operation */
+ ldap_get_option(racf->ld, LDAP_OPT_ERROR_NUMBER, &errcode);
+ switch (errcode) {
+ case LDAP_SERVER_DOWN:
+ /* Connection may have timed out, let's retry */
+ racf->connected = 0;
+ rc = ICTX_E_TRYAGAIN;
+ break;
+ default:
+ log_err("ldap_result unexpected failure: %s (0x%x)",
+ ldap_err2string(rc), rc);
+ rc = ICTX_E_ABORT;
+ }
+ goto end;
+ } else if (rc == 0) {
+ /* timeout reached */
+ log_warn("LDAP extended operation timed out");
+ rc = ICTX_E_ABORT;
+ goto end;
+ } else if (rc != LDAP_RES_EXTENDED) {
+ /* not an extended operation response! */
+ log_err("LDAP extended operation resulted in unexpected answer: 0x%x", rc);
+ rc = ICTX_E_ABORT;
+ goto free_result;
+ }
+
+ log_debug("Got LDAP Extended result");
+ /*
+ * we have an extended operation result
+ * first parse_result will check for errcode, later
+ * parse_extended_result will give us the oid and the BER value
+ */
+ rc = ldap_parse_result(racf->ld, result, &errcode, NULL,
+ &errmsg, NULL, NULL, 0);
+ if (rc != LDAP_SUCCESS) {
+ log_err("LDAP parse result internal failure (code 0x%x)",
+ rc);
+ rc = ICTX_E_ABORT;
+ goto free_result;
+ }
+
+ if (errcode != LDAP_SUCCESS) {
+ log_err("LDAP extended operation failed: %s", errmsg);
+ rc = ICTX_E_ABORT;
+ goto free_errmsg;
+ }
+
+ rc = ldap_parse_extended_result(racf->ld, result, &oid,
+ &bv_response, 0);
+ if (rc != LDAP_SUCCESS) {
+ log_err("Failed to parse ldap extended result (code 0x%x)",
+ rc);
+ rc = ICTX_E_ABORT;
+ goto free_errmsg;
+ }
+
+ if (oid && strcmp(oid, ICTX_OIDAUDITRESPONSE) != 0) {
+ /* oid == null shouldn't be a problem to log_err */
+ log_err("LDAP extended operation returned an invalid oid: %s", oid);
+ rc = ICTX_E_ABORT;
+ goto free_bv;
+ }
+
+ rc = decode_response(&response, bv_response);
+ if (rc != ICTX_SUCCESS) {
+ log_err("Error decoding extended operation response");
+ goto free_bv;
+ }
+
+ if (response.respMajor == RACF_MAJOR_SUCCESS) {
+ /* submission was successful, no further processing needed */
+ log_debug("Successfully submited Remote audit Request");
+ rc = ICTX_SUCCESS;
+ goto free_response;
+ } else if (response.respMajor == RACF_MAJOR_EMPTY) {
+ /* something is going on. Set error and stop processing */
+ log_warn("Warning - LDAP extended operation returned empty result");
+ rc = ICTX_E_ABORT;
+ goto free_response;
+ } else if (response.respMajor == RACF_MAJOR_WARNINGMODE ||
+ response.respMajor == RACF_MAJOR_NOTREQ)
+ rc = ICTX_SUCCESS; /* don't fail, but continue processing */
+ else
+ rc = ICTX_E_ABORT; /* set return code and continue processing */
+
+ /* If it's not success nor empty, let's check for errors in the response */
+ for (i = 0; i < response.numItems; i++) {
+ switch ((response.itemList[i])->majorCode) {
+ /* 0 <= Major Code <= 14 */
+ case RACF_MAJOR_SUCCESS:
+ break;
+ case RACF_MAJOR_WARNINGMODE:
+ case RACF_MAJOR_NOTREQ:
+ log_debug("Warning - LDAP extended operation returned '%s' for item %d",
+ racf_err2string((response.itemList[i])->majorCode),
+ (response.itemList[i])->itemTag);
+ log_debug("SAF code: 0x%x, RACF code: 0x%x, RACF reason: 0x%x",
+ (response.itemList[i])->minorCode1,
+ (response.itemList[i])->minorCode2,
+ (response.itemList[i])->minorCode3);
+ break;
+ case RACF_MAJOR_UNDETERMINED:
+ case RACF_MAJOR_UNAUTHORIZED:
+ case RACF_MAJOR_RACROUTE:
+ log_err("Error - LDAP extended operation returned '%s' for item %d",
+ racf_err2string((response.itemList[i])->majorCode),
+ (response.itemList[i])->itemTag);
+ log_err("SAF code: 0x%x, RACF code: 0x%x, RACF reason: 0x%x",
+ (response.itemList[i])->minorCode1,
+ (response.itemList[i])->minorCode2,
+ (response.itemList[i])->minorCode3);
+ break;
+ /* 16 <= Major Code <= 20 */
+ case RACF_MAJOR_VAL_ERR:
+ case RACF_MAJOR_ENC_ERR:
+ log_err("Error - LDAP extended operation returned '%s' for item %d",
+ racf_err2string((response.itemList[i])->majorCode),
+ (response.itemList[i])->itemTag);
+ log_err("Item field: %d, reson %d",
+ (response.itemList[i])->
+ minorCode1,
+ (response.itemList[i])->minorCode2);
+ break;
+ /* 24 <= Major code <= 100 */
+ case RACF_MAJOR_UNSUF_AUTH:
+ case RACF_MAJOR_EMPTY:
+ case RACF_MAJOR_INVALID_VER:
+ case RACF_MAJOR_INTERNAL_ERR:
+ log_err("Error - LDAP extended operation returned '%s' for item %d",
+ racf_err2string((response.itemList[i])->majorCode),
+ (response.itemList[i])->itemTag);
+ break;
+ default:
+ log_err("Error - LDAP extended operation returned an unknown Major code for item %d",
+ (response.itemList[i])->majorCode);
+ }
+ }
+
+free_response:
+ for (; response.numItems > 0; response.numItems--)
+ free(response.itemList[response.numItems - 1]);
+ free(response.itemList);
+
+free_bv:
+ if (bv_response)
+ ber_bvfree(bv_response);
+ if (oid)
+ ldap_memfree(oid);
+
+free_errmsg:
+ ldap_memfree(errmsg);
+
+free_result:
+ ldap_msgfree(result);
+
+end:
+ return rc;
+}
+
+static int decode_response(audit_response_t * r, struct berval *bv)
+{
+ BerElement *ber;
+ ber_len_t len;
+ int rc;
+
+ if (!bv) {
+ log_err("LDAP extended operation returned NULL message");
+ return ICTX_E_ABORT;
+ } else if ((ber = ber_init(bv)) == NULL) {
+ log_err("Error initializing BER response data");
+ return ICTX_E_ABORT;
+ }
+
+ log_debug("---Got an encoded request response:");
+ debug_bv(bv);
+
+ r->respVersion = 0;
+ r->respMajor = 0;
+ r->numItems = 0;
+ r->itemList = NULL;
+
+ rc = ber_scanf(ber, "{ii", &r->respVersion, &r->respMajor);
+ if (r->respVersion != ICTX_REQUESTVER) {
+ log_err("Invalid version returned by RACF server");
+ log_err("Should be %d, got %d", ICTX_REQUESTVER,
+ r->respVersion);
+ rc = ICTX_E_ABORT;
+ goto free_ber;
+ }
+
+ if (r->respMajor == RACF_MAJOR_SUCCESS ||
+ r->respMajor == RACF_MAJOR_EMPTY) {
+ rc = ICTX_SUCCESS;
+ /* No further processing required */
+ goto free_ber;
+ }
+
+ /* Inspect ber response otherwise */
+ while (ber_peek_tag(ber, &len) == LBER_SEQUENCE) {
+ r->numItems++;
+ r->itemList = (audit_resp_item_t **) realloc(r->itemList,
+ r->numItems *
+ sizeof
+ (audit_resp_item_t
+ *));
+ if (errno == ENOMEM) {
+ if (r->itemList)
+ free(r->itemList);
+ rc = ICTX_E_FATAL;
+ goto free_ber;
+ }
+
+ audit_resp_item_t *item = (audit_resp_item_t *)
+ malloc(sizeof(audit_resp_item_t));
+
+ if (!item) {
+ rc = ICTX_E_FATAL;
+ goto free_ber;
+ }
+
+ rc |= ber_scanf(ber, "{{iiiiii}}",
+ &item->version,
+ &item->itemTag,
+ &item->majorCode,
+ &item->minorCode1, &item->minorCode2,
+ &item->minorCode3);
+ r->itemList[r->numItems - 1] = item;
+ }
+ rc |= ber_scanf(ber, "}");
+
+ if (rc == -1) {
+ for (; r->numItems > 0; r->numItems--)
+ free(r->itemList[r->numItems - 1]);
+ free(r->itemList);
+ rc = ICTX_E_ABORT;
+ }
+ else
+ rc = ICTX_SUCCESS;
+
+free_ber:
+ ber_free(ber, 1);
+
+ return rc;
+}
diff -purN audit-1.6.2/audisp/plugins/racf/racf-ldap.h audit-1.6.2_racf/audisp/plugins/racf/racf-ldap.h
--- audit-1.6.2/audisp/plugins/racf/racf-ldap.h 1969-12-31 21:00:00.000000000 -0300
+++ audit-1.6.2_racf/audisp/plugins/racf/racf-ldap.h 2007-10-10 10:26:18.000000000 -0300
@@ -0,0 +1,310 @@
+/***************************************************************************
+ * Copyright (C) 2007 International Business Machines Corp. *
+ * All Rights Reserved. *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ * *
+ * Authors: *
+ * Klaus Heinrich Kiwi <klausk(a)br.ibm.com> *
+ ***************************************************************************/
+
+#ifndef _RACF_LDAP_H
+#define _RACF_LDAP_H
+
+#include <lber.h>
+#include <ldap.h>
+
+
+/***************************************************************************
+ * LDAP Extended Op OID for ICTX Audit *
+ ***************************************************************************/
+/* ICTX EIM component AUDIT Request OID */
+#define ICTX_OIDAUDITREQUEST "1.3.18.0.2.12.68"
+
+/* The AUDIT Response OID */
+#define ICTX_OIDAUDITRESPONSE "1.3.18.0.2.12.69"
+
+/* This implementation version
+ Request and response must match this */
+#define ICTX_REQUESTVER 0x1
+
+/* Needed for BER-encoding */
+#define ASN1_IA5STRING_TAG 0x16
+
+/***************************************************************************
+ * the ASN.1 struct for the remote audit request and response: *
+ * *
+ * RequestValue ::= SEQUENCE { *
+ * RequestVersion INTEGER, *
+ * ItemList SEQUENCE OF *
+ * Item SEQUENCE { *
+ * ItemVersion INTEGER, *
+ * ItemTag INTEGER, *
+ * LinkValue OCTET STRING SIZE(8), *
+ * Violation BOOLEAN, *
+ * Event INTEGER, *
+ * Qualifier INTEGER, *
+ * Class IA5String, *
+ * Resource IA5String, *
+ * LogString IA5String, *
+ * DatafieldList SEQUENCE OF *
+ * DataField SEQUENCE { *
+ * TYPE INTEGER, *
+ * VALUE IA5STRING *
+ * } *
+ * } *
+ * } *
+ * *
+ * Response ::= SEQUENCE { *
+ * Version INTEGER, *
+ * ResponseCode INTEGER, *
+ * ItemList SEQUENCE OF *
+ * Item SEQUENCE { *
+ * ItemVersion INTEGER, *
+ * ItemTag INTEGER, *
+ * MajorCode INTEGER, *
+ * MinorCode1 INTEGER, *
+ * MinorCode2 INTEGER, *
+ * MinorCode3 INTEGER *
+ * } *
+ * } *
+ ***************************************************************************/
+
+/***************************************************************************
+ * RACF Remote Audit Minor return codes meaning
+
+Major Code Meaning
+---------- ---------------------------------------------------------
+0-14 - MinorCode1 is the SAF return code
+ - MinorCode2 is the RACF return code
+ - MinorCode3 is the RACF reason code
+
+16-20 - MinorCode1 identifies the extended operation request
+ parameter number (see audit request ASN.1 definition):
+ 0 - Item
+ 1 - ItemVersion
+ 2 - ItemTag
+ 3 - LinkValue
+ 4 - Violation
+ 5 - Event
+ 6 - Qualifier
+ 7 - Class
+ 8 - Resource
+ 9 - LogString
+ 10 - DataFieldList
+ 11 - DataField *
+ 12 - TYPE *
+ 13 - VALUE *
+ - MinorCode2 indicates one of the Following:
+ 32 - incorrect length
+ 36 - incorrect value
+ 40 - encoding error
+ - MinorCode3 has no defined meaning
+
+24-100 - MinorCode1 has no defined meaning
+ - MinorCode2 has no defined meaning
+ - MinorCode3 has no defined meaning
+
+* There can be multiple DataField, TYPEs and VALUEs in a request. If any of them is bad
+ you get the same 11, 12 or 13 MinorCode1. There is no further breakdown of which one
+ is bad.
+
+ ***************************************************************************/
+
+/***************************************************************************
+ * Audit Request 'event' field meaning *
+ ***************************************************************************/
+#define RACF_EVENT_AUTHENTICATION 0x1
+#define RACF_EVENT_AUTHORIZATION 0x2
+#define RACF_EVENT_AUTHORIZATION_MAPPING 0x3
+#define RACF_EVENT_KEY_MGMT 0x4
+#define RACF_EVENT_POLICY_MGMT 0x5
+#define RACF_EVENT_ADMIN_CONFIG 0x6
+#define RACF_EVENT_ADMIN_ACTION 0x7
+
+/***************************************************************************
+ * Audit Request 'qualifier' field meaning *
+ ***************************************************************************/
+#define RACF_QUALIF_SUCCESS 0x0
+#define RACF_QUALIF_INFO 0x1
+#define RACF_QUALIF_WARN 0x2
+#define RACF_QUALIF_FAIL 0x3
+
+/***************************************************************************
+ * Relocate types for Audit Request *
+ ***************************************************************************/
+/* SAF identifier for bind user */
+#define RACF_RELOC_SAF_BIND_USER 100
+
+/* Reguestor's bind user identifier */
+#define RACF_RELOC_REQ_BIND_USER 101
+
+/* Originating security domain */
+#define RACF_RELOC_ORIG_SECURITY 102
+
+/* Originating registry / realm */
+#define RACF_RELOC_ORIG_REALM 103
+
+/* Originating user name */
+#define RACF_RELOC_ORIG_USER 104
+
+/* Mapped security domain */
+#define RACF_RELOC_MAPPED_SECURITY 105
+
+/* Mapped registry / realm */
+#define RACF_RELOC_MAPPED_REALM 106
+
+/* Mapped user name */
+#define RACF_RELOC_MAPPED_USER 107
+
+/* Operation performed */
+#define RACF_RELOC_OPERATION 108
+
+/* Mechanism / object name */
+#define RACF_RELOC_OBJECT 109
+
+/* Method / function used */
+#define RACF_RELOC_FUNCTION 110
+
+/* Key / certificate name */
+#define RACF_RELOC_CERTIFICATE 111
+
+/* Caller subject initiating security event */
+#define RACF_RELOC_INITIATING_EVENT 112
+
+/* Date and time security event occurred */
+#define RACF_RELOC_TIMESTAMP 113
+
+/* Application specific data. (i.e. Other) */
+#define RACF_RELOC_OTHER 114
+
+/***************************************************************************
+ * RACF Remote Audit Major return codes *
+ ***************************************************************************/
+#define RACF_MAJOR_SUCCESS 0
+
+/* Event was logged, with warnings */
+#define RACF_MAJOR_WARNINGMODE 2
+
+/* No logging required
+ No audit controls are set to require it */
+#define RACF_MAJOR_NOTREQ 3
+
+/* Class not active/ractlisted,
+ covering profile not found or
+ RACF is not installed */
+#define RACF_MAJOR_UNDETERMINED 4
+
+/* The user does not have authority the R_auditx service.
+ The userid associated with the LDAP server must have
+ at least READ access to the FACILITY class profile IRR.RAUDITX. */
+#define RACF_MAJOR_UNAUTHORIZED 8
+
+
+/* The R_auditx service returned an unexpected error.
+ Compare the returned minor codes with the SAF RACF codes
+ documented in Security Server Callable Services */
+#define RACF_MAJOR_RACROUTE 12
+
+/* A value specified in the extended operation request is
+ incorrect or unsupported. Check the returned minor codes
+ to narrow the reason */
+#define RACF_MAJOR_VAL_ERR 16
+
+/* A DER decoding error was encountered in an item.
+ Processing Terminated. Partial results may be returned */
+#define RACF_MAJOR_ENC_ERR 20
+
+/* The requestor does not have sufficient authority for the
+ requested function. The userid associated with the LDAP bind
+ user must have at least READ access to the FACILITY class
+ profile IRR.LDAP.REMOTE.AUDIT. */
+#define RACF_MAJOR_UNSUF_AUTH 24
+
+/* No items are found within the ItemList sequence of the extended
+ operation request, so no response items are returned */
+#define RACF_MAJOR_EMPTY 28
+
+/* Invalid RequestVersion */
+#define RACF_MAJOR_INVALID_VER 61
+
+/* An internal error was encountered within the ICTX component */
+#define RACF_MAJOR_INTERNAL_ERR 100
+
+/***************************************************************************
+ * Some standard sizes for remote audit request items *
+ ***************************************************************************/
+#define RACF_LINK_VALUE_SIZE 8
+#define RACF_CLASS_SIZE 8
+#define RACF_RESOURCE_SIZE 240
+#define RACF_LOGSTRING_SIZE 200
+
+
+/***************************************************************************
+ * Some standard Error defines *
+ ***************************************************************************/
+#define ICTX_SUCCESS 0x00
+
+/* maybe a temporary failure? */
+#define ICTX_E_TRYAGAIN 0x01
+
+/* permanent failure - abort event submission */
+#define ICTX_E_ABORT 0x02
+
+/* Fatal failure - abort program */
+#define ICTX_E_FATAL 0x03
+
+/* generic error */
+#define ICTX_E_ERROR 0x10
+
+/***************************************************************************
+ * structure representing an RACF session *
+ ***************************************************************************/
+typedef struct opaque
+{
+ char *server;
+ unsigned int port;
+ char *user;
+ char *password;
+ unsigned int timeout;
+ LDAP *ld;
+ int connected;
+} RACF;
+
+/***************************************************************************
+ * LDAP XOP operations *
+ ***************************************************************************/
+/*
+ * Initializes RACF connection, binds to RACF Server
+ * Args are:
+ * server, bind user, bind password, server port, timeout
+ * Caller must call racf_destroy() to free memory allocation
+ */
+int racf_init(RACF *, char *, int, char *, char *, int);
+
+/*
+ * Uninitializes RACF connection
+ */
+void racf_destroy(RACF *);
+
+/*
+ * sync submit request - possibly reconnect to server
+ * if the connection if found to be dead
+ */
+int submit_request_s(RACF *, BerElement *);
+
+
+#endif /* _RACF_LDAP_H */
17 years, 2 months
[PATCH 2/8][v2] audisp-racf plugin - configuration interface
by Klaus Heinrich Kiwi
This patch brings the configuration interface for the racf-plugin. This
is taken directly from Steve's audit dispatcher code, only adapted for
this specific plugin.
Signed-off-by: Klaus Heinrich Kiwi <klausk(a)br.ibm.com>
diff -purN audit-1.6.2/audisp/plugins/racf/racf-config.c audit-1.6.2_racf/audisp/plugins/racf/racf-config.c
--- audit-1.6.2/audisp/plugins/racf/racf-config.c 1969-12-31 21:00:00.000000000 -0300
+++ audit-1.6.2_racf/audisp/plugins/racf/racf-config.c 2007-10-10 10:26:18.000000000 -0300
@@ -0,0 +1,442 @@
+/***************************************************************************
+ * Copyright (C) 2007 International Business Machines Corp. *
+ * All Rights Reserved. *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ * *
+ * Authors: *
+ * Klaus Heinrich Kiwi <klausk(a)br.ibm.com> *
+ * based on code by Steve Grubb <sgrubb(a)redhat.com> *
+ ***************************************************************************/
+
+#include "racf-config.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include "racf-log.h"
+
+/* Local prototypes */
+struct nv_pair
+{
+ const char *name;
+ const char *value;
+ const char *option;
+};
+
+struct kw_pair
+{
+ const char *name;
+ int (*parser) (struct nv_pair *, int, racf_conf_t *);
+ int max_options;
+};
+
+struct nv_list
+{
+ const char *name;
+ int option;
+};
+
+static char *get_line(FILE *, char *);
+static int nv_split(char *, struct nv_pair *);
+static const struct kw_pair *kw_lookup(const char *);
+static int server_parser(struct nv_pair *, int, racf_conf_t *);
+static int port_parser(struct nv_pair *, int, racf_conf_t *);
+static int timeout_parser(struct nv_pair *, int, racf_conf_t *);
+static int user_parser(struct nv_pair *, int, racf_conf_t *);
+static int password_parser(struct nv_pair *, int, racf_conf_t *);
+static int q_depth_parser(struct nv_pair *, int, racf_conf_t *);
+static int sanity_check(racf_conf_t *, const char *);
+
+static const struct kw_pair keywords[] = {
+ {"server", server_parser, 0},
+ {"port", port_parser, 0},
+ {"timeout", timeout_parser, 0},
+ {"user", user_parser, 0},
+ {"password", password_parser, 0},
+ {"q_depth", q_depth_parser, 0},
+ {NULL, NULL, 0}
+};
+
+
+
+/*
+ * Set everything to its default value
+*/
+void racf_clear_config(racf_conf_t * c)
+{
+ c->server = NULL;
+ c->port = 0;
+ c->user = NULL;
+ c->password = NULL;
+ c->timeout = 15;
+ c->q_depth = 64;
+ /* not re-setting counter */
+}
+
+int racf_load_config(racf_conf_t * c, char *file)
+{
+ int fd, rc, mode, lineno = 1;
+ struct stat st;
+ FILE *f;
+ char buf[128];
+
+ racf_clear_config(c);
+
+ /* open the file */
+ mode = O_RDONLY;
+ rc = open(file, mode);
+ if (rc < 0) {
+ if (errno != ENOENT) {
+ log_err("Error opening %s (%s)", file,
+ strerror(errno));
+ return 1;
+ }
+ log_warn("Config file %s doesn't exist, skipping", file);
+ return 1;
+ }
+ fd = rc;
+
+ /* check the file's permissions: owned by root, not world anything,
+ * not symlink.
+ */
+ if (fstat(fd, &st) < 0) {
+ log_err("Error fstat'ing config file (%s)",
+ strerror(errno));
+ close(fd);
+ return 1;
+ }
+ if (st.st_uid != 0) {
+ log_err("Error - %s isn't owned by root", file);
+ close(fd);
+ return 1;
+ }
+ if ((st.st_mode & (S_IRUSR | S_IWUSR | S_IRGRP)) !=
+ (S_IRUSR | S_IWUSR | S_IRGRP)) {
+ log_err("%s permissions should be 0640", file);
+ return 1;
+ }
+ if (!S_ISREG(st.st_mode)) {
+ log_err("Error - %s is not a regular file", file);
+ close(fd);
+ return 1;
+ }
+
+ /* it's ok, read line by line */
+ f = fdopen(fd, "r");
+ if (f == NULL) {
+ log_err("Error - fdopen failed (%s)", strerror(errno));
+ close(fd);
+ return 1;
+ }
+
+ while (get_line(f, buf)) {
+ /* convert line into name-value pair */
+ const struct kw_pair *kw;
+ struct nv_pair nv;
+
+ rc = nv_split(buf, &nv);
+ switch (rc) {
+ case 0: /* fine */
+ break;
+ case 1: /* not the right number of tokens. */
+ log_err("Wrong number of arguments for line %d in %s", lineno, file);
+ break;
+ case 2: /* no '=' sign */
+ log_err("Missing equal sign for line %d in %s",
+ lineno, file);
+ break;
+ default: /* something else went wrong... */
+ log_err("Unknown error for line %d in %s",
+ lineno, file);
+ break;
+ }
+ if (nv.name == NULL) {
+ lineno++;
+ continue;
+ }
+ if (nv.value == NULL) {
+ fclose(f);
+ return 1;
+ }
+
+ /* identify keyword or error */
+ kw = kw_lookup(nv.name);
+ if (kw->name == NULL) {
+ log_err("Unknown keyword \"%s\" in line %d of %s",
+ nv.name, lineno, file);
+ fclose(f);
+ return 1;
+ }
+
+ /* Check number of options */
+ if (kw->max_options == 0 && nv.option != NULL) {
+ log_err("Keyword \"%s\" has invalid option "
+ "\"%s\" in line %d of %s",
+ nv.name, nv.option, lineno, file);
+ fclose(f);
+ return 1;
+ }
+
+ /* dispatch to keyword's local parser */
+ rc = kw->parser(&nv, lineno, c);
+ if (rc != 0) {
+ fclose(f);
+ return 1; /* local parser puts message out */
+ }
+
+ lineno++;
+ }
+
+ fclose(f);
+ c->name = strdup(basename(file));
+ if (lineno > 1)
+ return sanity_check(c, file);
+ return 0;
+}
+
+static char *get_line(FILE * f, char *buf)
+{
+ if (fgets_unlocked(buf, 128, f)) {
+ /* remove newline */
+ char *ptr = strchr(buf, 0x0a);
+
+ if (ptr)
+ *ptr = 0;
+ return buf;
+ }
+ return NULL;
+}
+
+static int nv_split(char *buf, struct nv_pair *nv)
+{
+ /* Get the name part */
+ char *ptr;
+
+ nv->name = NULL;
+ nv->value = NULL;
+ nv->option = NULL;
+ ptr = strtok(buf, " ");
+ if (ptr == NULL)
+ return 0; /* If there's nothing, go to next line */
+ if (ptr[0] == '#')
+ return 0; /* If there's a comment, go to next line */
+ nv->name = ptr;
+
+ /* Check for a '=' */
+ ptr = strtok(NULL, " ");
+ if (ptr == NULL)
+ return 1;
+ if (strcmp(ptr, "=") != 0)
+ return 2;
+
+ /* get the value */
+ ptr = strtok(NULL, " ");
+ if (ptr == NULL)
+ return 1;
+ nv->value = ptr;
+
+ /* See if there's an option */
+ ptr = strtok(NULL, " ");
+ if (ptr) {
+ nv->option = ptr;
+
+ /* Make sure there's nothing else */
+ ptr = strtok(NULL, " ");
+ if (ptr)
+ return 1;
+ }
+
+ /* Everything is OK */
+ return 0;
+}
+
+static const struct kw_pair *kw_lookup(const char *val)
+{
+ int i = 0;
+
+ while (keywords[i].name != NULL) {
+ if (strcasecmp(keywords[i].name, val) == 0)
+ break;
+ i++;
+ }
+ return &keywords[i];
+}
+
+
+static int server_parser(struct nv_pair *nv, int line, racf_conf_t * c)
+{
+
+ if (nv->value == NULL)
+ c->server = NULL;
+ else
+ c->server = strdup(nv->value);
+
+ return 0;
+}
+
+static int port_parser(struct nv_pair *nv, int line, racf_conf_t * c)
+{
+ const char *ptr = nv->value;
+ unsigned long i;
+
+ /* check that all chars are numbers */
+ for (i = 0; ptr[i]; i++) {
+ if (!isdigit(ptr[i])) {
+ log_err("Value %s should only be numbers - line %d", nv->value, line);
+ return 1;
+ }
+ }
+
+ /* convert to unsigned long */
+ errno = 0;
+ i = strtoul(nv->value, NULL, 10);
+ if (errno) {
+ log_err("Error converting string to a number (%s) - line %d", strerror(errno), line);
+ return 1;
+ }
+
+ c->port = i;
+ return 0;
+
+}
+
+static int timeout_parser(struct nv_pair *nv, int line, racf_conf_t * c)
+{
+ const char *ptr = nv->value;
+ unsigned long i;
+
+ /* check that all chars are numbers */
+ for (i = 0; ptr[i]; i++) {
+ if (!isdigit(ptr[i])) {
+ log_err("Value %s should only be numbers - line %d", nv->value, line);
+ return 1;
+ }
+ }
+
+ /* convert to unsigned long */
+ errno = 0;
+ i = strtoul(nv->value, NULL, 10);
+ if (errno) {
+ log_err("Error converting string to a number (%s) - line %d", strerror(errno), line);
+ return 1;
+ }
+
+ c->timeout = i;
+ return 0;
+
+}
+
+
+static int user_parser(struct nv_pair *nv, int line, racf_conf_t * c)
+{
+
+ if (nv->value == NULL)
+ c->user = NULL;
+ else
+ c->user = strdup(nv->value);
+
+ return 0;
+}
+
+static int password_parser(struct nv_pair *nv, int line, racf_conf_t * c)
+{
+
+ if (nv->value == NULL)
+ c->password = NULL;
+ else
+ c->password = strdup(nv->value);
+
+ return 0;
+}
+
+static int q_depth_parser(struct nv_pair *nv, int line, racf_conf_t * c)
+{
+ const char *ptr = nv->value;
+ unsigned long i;
+
+ /* check that all chars are numbers */
+ for (i = 0; ptr[i]; i++) {
+ if (!isdigit(ptr[i])) {
+ log_err("Value %s should only be numbers - line %d", nv->value, line);
+ return 1;
+ }
+ }
+
+ /* convert to unsigned long */
+ errno = 0;
+ i = strtoul(nv->value, NULL, 10);
+ if (errno) {
+ log_err("Error converting string to a number (%s) - line %d", strerror(errno), line);
+ return 1;
+ }
+
+ if (i < 16 || i > 99999) {
+ log_err("q_depth must be between 16 and 99999");
+ return 1;
+ }
+
+ c->q_depth = i;
+ return 0;
+
+}
+
+
+/*
+ * Check configuration.At this point, all fields have been read.
+ * Returns 0 if no problems and 1 if problems detected.
+ */
+static int sanity_check(racf_conf_t * c, const char *file)
+{
+ /* Error checking */
+ if (!c->server) {
+ log_err("Error - no server hostname given");
+ return 1;
+ }
+
+ if (!c->user) {
+ log_err("Error - no bind user given");
+ return 1;
+ }
+
+ if (!c->password) {
+ log_err("Error - no password given");
+ return 1;
+ }
+
+ if (!c->timeout) {
+ log_err("Error - timeout can't be zero");
+ return 1;
+ }
+ return 0;
+}
+
+void racf_free_config(racf_conf_t * c)
+{
+
+ if (c == NULL)
+ return;
+
+ free((void *) c->server);
+ free((void *) c->user);
+ free((void *) c->password);
+ free((void *) c->name);
+}
diff -purN audit-1.6.2/audisp/plugins/racf/racf-config.h audit-1.6.2_racf/audisp/plugins/racf/racf-config.h
--- audit-1.6.2/audisp/plugins/racf/racf-config.h 1969-12-31 21:00:00.000000000 -0300
+++ audit-1.6.2_racf/audisp/plugins/racf/racf-config.h 2007-10-10 10:26:18.000000000 -0300
@@ -0,0 +1,48 @@
+/***************************************************************************
+ * Copyright (C) 2007 International Business Machines Corp. *
+ * All Rights Reserved. *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ * *
+ * Authors: *
+ * Klaus Heinrich Kiwi <klausk(a)br.ibm.com> *
+ * based on code by Steve Grubb <sgrubb(a)redhat.com> *
+ ***************************************************************************/
+
+#ifndef _RACF_CONFIG_H
+#define _RACF_CONFIG_H
+
+
+/***************************************************************************
+ * RACF Plugin configuration *
+ ***************************************************************************/
+typedef struct racf_conf
+{
+ char *name;
+ char *server;
+ unsigned int port;
+ char *user;
+ char *password;
+ long timeout;
+ unsigned int q_depth;
+ unsigned int counter;
+} racf_conf_t;
+
+void racf_clear_config(racf_conf_t *);
+int racf_load_config(racf_conf_t *, char *);
+void racf_free_config(racf_conf_t *);
+
+#endif /* _RACF_CONFIG_H */
17 years, 2 months
[PATCH 1/8][v2] audisp-racf plugin - Configuration and policy module files
by Klaus Heinrich Kiwi
This patch adds the configuration files and policy module sources needed
by the plugin.
The policy is not using newer interfaces so that it can be build for
RHEL5 GA.
There is a need for two separate configuration files: one for the audit
dispatcher and another for the plugin itself.
The plugin configuration includes server and authentication information,
thus it should not be readable by anyone but root. The default queue
size is to allow event bursts avoiding events drop.
The plugin comes disabled by default.
Signed-off-by: Klaus Heinrich Kiwi <klausk(a)br.ibm.com>
diff -purN audit-1.6.2/audisp/plugins/racf/policy/build.sh audit-1.6.2_racf/audisp/plugins/racf/policy/build.sh
--- audit-1.6.2/audisp/plugins/racf/policy/build.sh 1969-12-31 21:00:00.000000000 -0300
+++ audit-1.6.2_racf/audisp/plugins/racf/policy/build.sh 2007-10-10 10:26:18.000000000 -0300
@@ -0,0 +1,3 @@
+
+#!/bin/sh
+make -f /usr/share/selinux/devel/Makefile
diff -purN audit-1.6.2/audisp/plugins/racf/policy/install.sh audit-1.6.2_racf/audisp/plugins/racf/policy/install.sh
--- audit-1.6.2/audisp/plugins/racf/policy/install.sh 1969-12-31 21:00:00.000000000 -0300
+++ audit-1.6.2_racf/audisp/plugins/racf/policy/install.sh 2007-10-10 10:26:18.000000000 -0300
@@ -0,0 +1,4 @@
+/usr/sbin/semodule -i racf.pp
+
+/sbin/restorecon -F -v /sbin/audisp-racf
+
diff -purN audit-1.6.2/audisp/plugins/racf/policy/racf.fc audit-1.6.2_racf/audisp/plugins/racf/policy/racf.fc
--- audit-1.6.2/audisp/plugins/racf/policy/racf.fc 1969-12-31 21:00:00.000000000 -0300
+++ audit-1.6.2_racf/audisp/plugins/racf/policy/racf.fc 2007-10-10 10:26:18.000000000 -0300
@@ -0,0 +1,2 @@
+
+/sbin/audisp-racf -- gen_context(system_u:object_r:racf_exec_t,s0)
diff -purN audit-1.6.2/audisp/plugins/racf/policy/racf.if audit-1.6.2_racf/audisp/plugins/racf/policy/racf.if
--- audit-1.6.2/audisp/plugins/racf/policy/racf.if 1969-12-31 21:00:00.000000000 -0300
+++ audit-1.6.2_racf/audisp/plugins/racf/policy/racf.if 2007-10-10 10:26:18.000000000 -0300
@@ -0,0 +1,58 @@
+
+## <summary>policy for racf</summary>
+
+########################################
+## <summary>
+## Execute a domain transition to run racf.
+## </summary>
+## <param name="domain">
+## <summary>
+## Domain allowed to transition.
+## </summary>
+## </param>
+#
+interface(`racf_domtrans',`
+ gen_require(`
+ type racf_t;
+ type racf_exec_t;
+ ')
+
+ domain_auto_trans($1,racf_exec_t,racf_t);
+
+ allow $1 racf_t:fd use;
+ allow racf_t $1:fd use;
+ allow racf_t $1:fifo_file rw_file_perms;
+ allow racf_t $1:process sigchld;
+')
+
+########################################
+## <summary>
+## Execute racf in the racf domain, and
+## allow the specified role the racf domain.
+## </summary>
+## <param name="domain">
+## <summary>
+## Domain allowed access
+## </summary>
+## </param>
+## <param name="role">
+## <summary>
+## The role to be allowed the racf domain.
+## </summary>
+## </param>
+## <param name="terminal">
+## <summary>
+## The type of the role's terminal.
+## </summary>
+## </param>
+#
+interface(`racf_run',`
+ gen_require(`
+ type racf_t;
+ ')
+
+ racf_domtrans($1)
+ role $2 types racf_t;
+ dontaudit racf_t $3:chr_file rw_term_perms;
+')
+
diff -purN audit-1.6.2/audisp/plugins/racf/policy/racf.te audit-1.6.2_racf/audisp/plugins/racf/policy/racf.te
--- audit-1.6.2/audisp/plugins/racf/policy/racf.te 1969-12-31 21:00:00.000000000 -0300
+++ audit-1.6.2_racf/audisp/plugins/racf/policy/racf.te 2007-10-10 10:26:18.000000000 -0300
@@ -0,0 +1,55 @@
+policy_module(racf,1.0.0)
+
+########################################
+#
+# Declarations
+#
+
+type racf_t;
+type racf_exec_t;
+
+## selinux-policy_devel > 3:
+## racf_application_domain(racf_t, racf_exec_t)
+
+## RHEL5 series:
+init_system_domain(racf_t, racf_exec_t)
+
+role system_r types racf_t;
+
+
+########################################
+#
+# racf local policy
+#
+
+## internal communication is often done using fifo and unix sockets.
+allow racf_t self:fifo_file rw_file_perms;
+allow racf_t self:unix_stream_socket create_stream_socket_perms;
+## allow signals to self
+allow racf_t self:process signal;
+
+## audisp is in the auditd_t domain
+gen_require(`
+ type auditd_t;
+')
+
+## Allow auditd_t->racf_t transition
+racf_domtrans(auditd_t);
+
+## audisp execve pipe?
+allow racf_t auditd_t:unix_stream_socket { read write getattr };
+
+## audisp must be able to send signals to audisp-racf
+allow auditd_t racf_t:process signal;
+
+## Allow network access, name resolv
+auth_use_nsswitch(racf_t);
+
+##
+files_read_etc_files(racf_t)
+libs_use_ld_so(racf_t)
+libs_use_shared_libs(racf_t)
+miscfiles_read_localization(racf_t)
+logging_send_syslog_msg(racf_t)
+
+
diff -purN audit-1.6.2/audisp/plugins/racf/racf.conf audit-1.6.2_racf/audisp/plugins/racf/racf.conf
--- audit-1.6.2/audisp/plugins/racf/racf.conf 1969-12-31 21:00:00.000000000 -0300
+++ audit-1.6.2_racf/audisp/plugins/racf/racf.conf 2007-10-10 10:26:18.000000000 -0300
@@ -0,0 +1,10 @@
+# This is the configuration file for the audit-plugin-racf
+# server, user and password are required, everything else is
+# optional
+
+server = racf.server
+port = 389
+user = RACFUSER
+password = password
+timeout = 15
+q_depth = 64
diff -purN audit-1.6.2/audisp/plugins/racf/audisp-racf.conf audit-1.6.2_racf/audisp/plugins/racf/audisp-racf.conf
--- audit-1.6.2/audisp/plugins/racf/audisp-racf.conf 1969-12-31 21:00:00.000000000 -0300
+++ audit-1.6.2_racf/audisp/plugins/racf/audisp-racf.conf 2007-10-10 10:26:18.000000000 -0300
@@ -0,0 +1,13 @@
+# This is the audit dispatcher configuration
+# for the RACF audit plugin
+# Note that this specific plugin has a configuration
+# file of its own. The complete path for this
+# file must be entered as the argument for the
+# plugin in the 'args' field below
+
+active = no
+direction = out
+path = /sbin/audisp-racf
+type = always
+args = /etc/audisp/racf.conf
+format = string
17 years, 2 months
[PATCH 0/8][v2] audisp-racf plugin
by Klaus Heinrich Kiwi
List,
this is a reviewed version of patches sent a while ago (Sept. 28),
implementing a remote auditing plugin for IBM z/OS RACF using ITDS.
Changes from last version:
--------------------------
* Manual pages for audisp-racf(8) and racf.conf(5)
* Bundled racf.pp policy modules for strict, targeted and mls policies
(Thanks Dan Walsh)
* Better signal and queue handling (thanks James Antill)
* Spec file now building audispd-plugins package
TODO (for future versions):
-----
* store-and-forward support in case of a network outage
Comments are (very) welcome. Steve, do you feel it is ready for upstream
merge?
Klaus
17 years, 2 months
[PATCH 4/3] Audit: add argc and len fields for split records
by Eric Paris
To make it possible for userspace tools to verify that all of the args
were successfully logged add 2 new pieces of information to the execve
audit messages:
1) All messages now start with argc=%d before the logging of a0.
2) When a single large argument is split into multiple records the first
of those records will now include a lenX=%d stating the number of bytes
in the original aX argument.
example:
record1: argc=2 a0=test_file
record2: len1=12k a1[0]=first 7.5k chunk of a1 argument
record3: a1[1]=remainder of a1 argument
Signed-off-by: Eric Paris <eparis(a)redhat.com>
kernel/auditsc.c | 5 +++++
1 files changed, 5 insertions(+), 0 deletions(-)
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index b411737..f8ac79b 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -836,6 +836,8 @@ static void audit_log_execve_info(struct audit_context *context,
p = (const char __user *)axi->mm->arg_start;
+ audit_log_format(*ab, "argc=%d ", axi->argc);
+
for (i = 0; i < axi->argc; i++, p += len) {
char tmp_buf[12];
/* how many digits are in i? */
@@ -888,6 +890,9 @@ static void audit_log_execve_info(struct audit_context *context,
kfree(buf);
return;
}
+ if (j == 0)
+ audit_log_format(*ab, "len%d=%ld ", i,
+ len + tmplen);
audit_log_format(*ab, "a%d[%d]=", i, j);
audit_log_untrustedstring(*ab, buf);
audit_log_format(*ab, "\n");
17 years, 2 months
syscall names are architecture independent
by Matthew Booth
On RHEL 4 U5 x86_64, if you have the following rule:
-a entry,always -S removexattr
you'd expect the result to be that the removexattr call is audited. This
isn't quite the case. What this actually means is 'audit system call
197'. The effect of this is to audit 64 bit removexattr calls and 32 bit
fstat64 calls.
I can see why this is the case, however this is clearly both undesirable
and far from intuitive. I'm not entirely sure what the solution should
be, but a big warning in the man page might be a good start :) As a
general rule, this highlights that it's always essential to additionally
filter by architecture on x86_64.
Matt
--
Matthew Booth, RHCA, RHCSS
Red Hat, Global Professional Services
M: +44 (0)7977 267231
GPG ID: D33C3490
GPG FPR: 3733 612D 2D05 5458 8A8A 1600 3441 EA19 D33C 3490
17 years, 2 months
[PATCH 2/2] Audit: remove the limit on execve arguments when audit is running
by Eric Paris
Remove the limitation on argv size. The audit system now logs arguments 8k at a
time so the attempt to keep the size of the execve args smaller than one netlink
message is no longer a requirement.
Signed-off-by: Eric Paris <eparis(a)redhat.com>
---
kernel/auditsc.c | 10 ----------
kernel/sysctl.c | 11 -----------
2 files changed, 0 insertions(+), 21 deletions(-)
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index f9f61db..6627fce 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -1876,8 +1876,6 @@ int __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode
return 0;
}
-int audit_argv_kb = 32;
-
int audit_bprm(struct linux_binprm *bprm)
{
struct audit_aux_data_execve *ax;
@@ -1886,14 +1884,6 @@ int audit_bprm(struct linux_binprm *bprm)
if (likely(!audit_enabled || !context || context->dummy))
return 0;
- /*
- * Even though the stack code doesn't limit the arg+env size any more,
- * the audit code requires that _all_ arguments be logged in a single
- * netlink skb. Hence cap it :-(
- */
- if (bprm->argv_len > (audit_argv_kb << 10))
- return -E2BIG;
-
ax = kmalloc(sizeof(*ax), GFP_KERNEL);
if (!ax)
return -ENOMEM;
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 53a456e..88e5d06 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -77,7 +77,6 @@ extern int percpu_pagelist_fraction;
extern int compat_log;
extern int maps_protect;
extern int sysctl_stat_interval;
-extern int audit_argv_kb;
/* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */
static int maxolduid = 65535;
@@ -347,16 +346,6 @@ static ctl_table kern_table[] = {
.mode = 0644,
.proc_handler = &proc_dointvec,
},
-#ifdef CONFIG_AUDITSYSCALL
- {
- .ctl_name = CTL_UNNUMBERED,
- .procname = "audit_argv_kb",
- .data = &audit_argv_kb,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = &proc_dointvec,
- },
-#endif
{
.ctl_name = KERN_CORE_PATTERN,
.procname = "core_pattern",
17 years, 2 months