aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/audit/audisp/plugins/zos-remote
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/audit/audisp/plugins/zos-remote')
-rw-r--r--framework/src/audit/audisp/plugins/zos-remote/Makefile.am52
-rw-r--r--framework/src/audit/audisp/plugins/zos-remote/audispd-zos-remote.conf14
-rw-r--r--framework/src/audit/audisp/plugins/zos-remote/zos-remote-config.c443
-rw-r--r--framework/src/audit/audisp/plugins/zos-remote/zos-remote-config.h48
-rw-r--r--framework/src/audit/audisp/plugins/zos-remote/zos-remote-ldap.c608
-rw-r--r--framework/src/audit/audisp/plugins/zos-remote/zos-remote-ldap.h312
-rw-r--r--framework/src/audit/audisp/plugins/zos-remote/zos-remote-log.c109
-rw-r--r--framework/src/audit/audisp/plugins/zos-remote/zos-remote-log.h58
-rw-r--r--framework/src/audit/audisp/plugins/zos-remote/zos-remote-plugin.c580
-rw-r--r--framework/src/audit/audisp/plugins/zos-remote/zos-remote-queue.c144
-rw-r--r--framework/src/audit/audisp/plugins/zos-remote/zos-remote-queue.h38
-rw-r--r--framework/src/audit/audisp/plugins/zos-remote/zos-remote.conf10
12 files changed, 2416 insertions, 0 deletions
diff --git a/framework/src/audit/audisp/plugins/zos-remote/Makefile.am b/framework/src/audit/audisp/plugins/zos-remote/Makefile.am
new file mode 100644
index 00000000..ac83a74d
--- /dev/null
+++ b/framework/src/audit/audisp/plugins/zos-remote/Makefile.am
@@ -0,0 +1,52 @@
+# Makefile.am--
+# Copyright (C) 2007,2008 International Business Machines Corp.
+# Copyright (C) 2011, 2015 Red Hat., Durham, North Carolina.
+# 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@br.ibm.com>
+#
+
+AM_CPPFLAGS = -I${top_srcdir} -I${top_srcdir}/lib -I${top_srcdir}/auparse
+CONFIG_CLEAN_FILES = *.rej *.orig
+AUTOMAKE_OPTIONS = no-dependencies
+EXTRA_DIST = zos-remote.conf audispd-zos-remote.conf
+LIBS = -L${top_builddir}/auparse -lauparse
+LDADD = -lpthread -lldap -llber $(CAPNG_LDADD)
+dispatcher_confdir = $(sysconfdir)/audisp
+plugin_confdir=$(dispatcher_confdir)/plugins.d
+plugin_conf = zos-remote.conf
+dispatcher_conf = audispd-zos-remote.conf
+sbin_PROGRAMS = audispd-zos-remote
+
+noinst_HEADERS = zos-remote-log.h zos-remote-ldap.h zos-remote-config.h \
+ zos-remote-queue.h
+audispd_zos_remote_SOURCES = zos-remote-plugin.c zos-remote-log.c \
+ zos-remote-ldap.c zos-remote-config.c zos-remote-queue.c
+audispd_zos_remote_CFLAGS = -W -Wall -Wundef -D_GNU_SOURCE -fPIE -DPIE
+audispd_zos_remote_LDFLAGS = -pie -Wl,-z,relro -Wl,-z,now
+
+install-data-hook:
+ mkdir -p -m 0750 ${DESTDIR}${plugin_confdir}
+ $(INSTALL_DATA) -D -m 640 ${srcdir}/$(plugin_conf) \
+ ${DESTDIR}${dispatcher_confdir}
+ $(INSTALL_DATA) -D -m 640 ${srcdir}/$(dispatcher_conf) \
+ ${DESTDIR}${plugin_confdir}
+
+uninstall-hook:
+ rm ${DESTDIR}${plugin_confdir}/$(dispatcher_conf)
+ rm ${DESTDIR}${dispatcher_confdir}/$(plugin_conf)
diff --git a/framework/src/audit/audisp/plugins/zos-remote/audispd-zos-remote.conf b/framework/src/audit/audisp/plugins/zos-remote/audispd-zos-remote.conf
new file mode 100644
index 00000000..13aef2ce
--- /dev/null
+++ b/framework/src/audit/audisp/plugins/zos-remote/audispd-zos-remote.conf
@@ -0,0 +1,14 @@
+# This is the configuration for the audispd-zos-remote
+# audit dispatcher plugin - See audispd(8)
+#
+# 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
+# See audispd-zos-remote(8)
+
+active = no
+direction = out
+path = /sbin/audispd-zos-remote
+type = always
+args = /etc/audisp/zos-remote.conf
+format = string
diff --git a/framework/src/audit/audisp/plugins/zos-remote/zos-remote-config.c b/framework/src/audit/audisp/plugins/zos-remote/zos-remote-config.c
new file mode 100644
index 00000000..b92dc778
--- /dev/null
+++ b/framework/src/audit/audisp/plugins/zos-remote/zos-remote-config.c
@@ -0,0 +1,443 @@
+/***************************************************************************
+ * 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@br.ibm.com> *
+ * based on code by Steve Grubb <sgrubb@redhat.com> *
+ ***************************************************************************/
+
+#include "zos-remote-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 "zos-remote-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, plugin_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, plugin_conf_t *);
+static int port_parser(struct nv_pair *, int, plugin_conf_t *);
+static int timeout_parser(struct nv_pair *, int, plugin_conf_t *);
+static int user_parser(struct nv_pair *, int, plugin_conf_t *);
+static int password_parser(struct nv_pair *, int, plugin_conf_t *);
+static int q_depth_parser(struct nv_pair *, int, plugin_conf_t *);
+static int sanity_check(plugin_conf_t *);
+
+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}
+};
+
+#define UNUSED(x) (void)(x)
+
+/*
+ * Set everything to its default value
+*/
+void plugin_clear_config(plugin_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 plugin_load_config(plugin_conf_t * c, const char *file)
+{
+ int fd, rc, mode, lineno = 1;
+ struct stat st;
+ FILE *f;
+ char buf[128];
+
+ plugin_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);
+ close(fd);
+ 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);
+ 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, *saved;
+
+ nv->name = NULL;
+ nv->value = NULL;
+ nv->option = NULL;
+ ptr = strtok_r(buf, " ", &saved);
+ 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_r(NULL, " ", &saved);
+ if (ptr == NULL)
+ return 1;
+ if (strcmp(ptr, "=") != 0)
+ return 2;
+
+ /* get the value */
+ ptr = strtok_r(NULL, " ", &saved);
+ if (ptr == NULL)
+ return 1;
+ nv->value = ptr;
+
+ /* See if there's an option */
+ ptr = strtok_r(NULL, " ", &saved);
+ if (ptr) {
+ nv->option = ptr;
+
+ /* Make sure there's nothing else */
+ ptr = strtok_r(NULL, " ", &saved);
+ 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, plugin_conf_t * c)
+{
+ UNUSED(line);
+ 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, plugin_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, plugin_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, plugin_conf_t * c)
+{
+ UNUSED(line);
+ 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, plugin_conf_t * c)
+{
+ UNUSED(line);
+ 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, plugin_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(plugin_conf_t * c)
+{
+ /* 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 plugin_free_config(plugin_conf_t * c)
+{
+
+ if (c == NULL)
+ return;
+
+ free((void *) c->server);
+ free((void *) c->user);
+ free((void *) c->password);
+ free((void *) c->name);
+}
diff --git a/framework/src/audit/audisp/plugins/zos-remote/zos-remote-config.h b/framework/src/audit/audisp/plugins/zos-remote/zos-remote-config.h
new file mode 100644
index 00000000..82bf365f
--- /dev/null
+++ b/framework/src/audit/audisp/plugins/zos-remote/zos-remote-config.h
@@ -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@br.ibm.com> *
+ * based on code by Steve Grubb <sgrubb@redhat.com> *
+ ***************************************************************************/
+
+#ifndef _ZOS_REMOTE_CONFIG_H
+#define _ZOS_REMOTE_CONFIG_H
+
+
+/***************************************************************************
+ * z/OS Remote-services Plugin configuration *
+ ***************************************************************************/
+typedef struct plugin_conf
+{
+ char *name;
+ char *server;
+ unsigned int port;
+ char *user;
+ char *password;
+ long timeout;
+ unsigned int q_depth;
+ unsigned int counter;
+} plugin_conf_t;
+
+void plugin_clear_config(plugin_conf_t *);
+int plugin_load_config(plugin_conf_t *, const char *);
+void plugin_free_config(plugin_conf_t *);
+
+#endif /* _ZOS_REMOTE_CONFIG_H */
diff --git a/framework/src/audit/audisp/plugins/zos-remote/zos-remote-ldap.c b/framework/src/audit/audisp/plugins/zos-remote/zos-remote-ldap.c
new file mode 100644
index 00000000..209743f3
--- /dev/null
+++ b/framework/src/audit/audisp/plugins/zos-remote/zos-remote-ldap.c
@@ -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@br.ibm.com> *
+ ***************************************************************************/
+
+#include "zos-remote-ldap.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "zos-remote-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;
+
+
+/***************************************************************************
+ * z/OS Remote-services Major return code handling *
+ ***************************************************************************/
+struct zos_remote_error
+{
+ int code;
+ char *str;
+};
+
+static struct zos_remote_error zos_remote_errlist[] = {
+ {ZOS_REMOTE_MAJOR_SUCCESS, "Success"},
+ {ZOS_REMOTE_MAJOR_WARNINGMODE, "WARNINGMODE - Event was logged, with warnings"},
+ {ZOS_REMOTE_MAJOR_NOTREQ, "NOTREQ - No logging required"},
+ {ZOS_REMOTE_MAJOR_UNDETERMINED, "UNDETERMINED - Undetermined result"},
+ {ZOS_REMOTE_MAJOR_UNAUTHORIZED, "UNAUTHORIZED - The user does not have authority the R_auditx service"},
+ {ZOS_REMOTE_MAJOR_RACROUTE, "RACROUTE - The R_auditx service returned an unexpected error"},
+ {ZOS_REMOTE_MAJOR_VAL_ERR, "VAL_ERR - Value error in request"},
+ {ZOS_REMOTE_MAJOR_ENC_ERR, "ENC_ERR - DER decoding error in request"},
+ {ZOS_REMOTE_MAJOR_UNSUF_AUTH, "UNSUF_AUTH - The user has unsuficient authority for the requested function"},
+ {ZOS_REMOTE_MAJOR_EMPTY, "EMPTY - Empty request received - No items found within the ItemList"},
+ {ZOS_REMOTE_MAJOR_INVALID_VER, "INVALID_VER - Invalid RequestVersion"},
+ {ZOS_REMOTE_MAJOR_INTERNAL_ERR, "INTERNAL_ERR - An internal error was encountered within the ICTX component"},
+ {-1, NULL}
+};
+
+/***************************************************************************
+ * Internal functions prototypes *
+ ***************************************************************************/
+static int _zos_remote_init(ZOS_REMOTE *);
+static void _zos_remote_destroy(ZOS_REMOTE *);
+static int zos_remote_connect(ZOS_REMOTE *);
+static void zos_remote_disconnect(ZOS_REMOTE *);
+static int submit_xop_s(ZOS_REMOTE *, struct berval *);
+static int decode_response(audit_response_t *, struct berval *);
+
+/***************************************************************************
+ * Exported functions *
+ ***************************************************************************/
+int submit_request_s(ZOS_REMOTE *zos_remote, 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(zos_remote, &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--;
+ _zos_remote_destroy(zos_remote);
+ rc = _zos_remote_init(zos_remote);
+ 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 zos_remote_init(ZOS_REMOTE *zos_remote, const char *server, int port,
+ const char *user, const char *password, int timeout)
+{
+ zos_remote->server = strdup(server);
+ zos_remote->port = port;
+ zos_remote->user = strdup(user);
+ zos_remote->password = strdup(password);
+ zos_remote->timeout = timeout;
+ zos_remote->connected = 0;
+
+ if (!zos_remote->server || !zos_remote->user || !zos_remote->password) {
+ log_err("Error allocating memory for session members");
+ return ICTX_E_FATAL;
+ }
+
+ return _zos_remote_init(zos_remote);
+}
+
+void zos_remote_destroy(ZOS_REMOTE *zos_remote)
+{
+ _zos_remote_destroy(zos_remote);
+
+ free(zos_remote->server);
+ free(zos_remote->user);
+ free(zos_remote->password);
+}
+
+char *zos_remote_err2string(int err)
+{
+ int i;
+
+ for (i = 0; zos_remote_errlist[i].str != NULL; i++) {
+ if (err == zos_remote_errlist[i].code)
+ return zos_remote_errlist[i].str;
+ }
+ return "Unknown error";
+}
+
+/***************************************************************************
+ * Internal Functions *
+ ***************************************************************************/
+static int _zos_remote_init(ZOS_REMOTE *zos_remote)
+{
+ int version, rc;
+ char *uri = NULL;
+
+#ifdef LDAP_DEPRECATED
+
+ log_debug("Initializing z/OS Remote-services LDAP connection at ldap://%s:%d",
+ zos_remote->server, zos_remote->port);
+ zos_remote->ld = ldap_init(zos_remote->server
+ zos_remote->port ? zos_remote->port : LDAP_PORT);
+ if (zos_remote->ld == NULL) {
+ log_err("Error initializing LDAP session: %s",
+ strerror(errno));
+ rc = ICTX_E_FATAL;
+ goto end;
+ }
+#else
+ /* build ldap URI */
+ if (zos_remote->port == 0 || zos_remote->port == LDAP_PORT)
+ rc = asprintf(&uri, "ldap://%s", zos_remote->server);
+ else
+ rc = asprintf(&uri, "ldap://%s:%d", zos_remote->server,
+ zos_remote->port);
+
+ if (rc == -1) {
+ log_err("Out of memory building LDAP server URI");
+ rc = ICTX_E_FATAL;
+ uri = NULL;
+ goto end;
+ }
+
+ log_debug("Initializing z/OS Remote-services LDAP connection at %s", uri);
+ /* Get a handle to an LDAP connection */
+ rc = ldap_initialize(&zos_remote->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(zos_remote->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(zos_remote->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(zos_remote->ld, NULL, NULL);
+ zos_remote->ld = NULL;
+
+free_uri:
+ free(uri);
+
+end:
+ return rc;
+}
+
+static void _zos_remote_destroy(ZOS_REMOTE *zos_remote)
+{
+ zos_remote_disconnect(zos_remote);
+ zos_remote->ld = NULL;
+}
+
+static int zos_remote_connect(ZOS_REMOTE *zos_remote)
+{
+ struct berval cred;
+ int rc;
+ char bindusr[255];
+
+ snprintf(bindusr, 255, "racfid=%s,cn=ictx", zos_remote->user);
+
+ log_debug("Attempting BIND. User '%s', password '<not shown>'",
+ bindusr);
+
+ cred.bv_val = (char *) zos_remote->password;
+ cred.bv_len = strlen(zos_remote->password);
+
+ rc = ldap_sasl_bind_s(zos_remote->ld, bindusr,
+ LDAP_SASL_SIMPLE, &cred,
+ NULL, NULL, NULL);
+
+
+ switch (rc) {
+ case LDAP_SUCCESS:
+ log_debug("LDAP BIND succeeded");
+ zos_remote->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("z/OS Remote-services connection failed: %s",
+ ldap_err2string(rc));
+ rc = ICTX_E_TRYAGAIN;
+ break;
+ default:
+ log_err("Error - z/OS Remote-services initialization failed: %s",
+ ldap_err2string(rc));
+ rc = ICTX_E_FATAL;
+ }
+
+ return rc;
+}
+
+
+static void zos_remote_disconnect(ZOS_REMOTE *zos_remote)
+{
+ if (zos_remote->ld) {
+ log_debug("Unbinding LDAP session");
+
+#ifdef LDAP_DEPRECATED
+ ldap_unbind(zos_remote->ld);
+#else
+ ldap_unbind_ext_s(zos_remote->ld, NULL, NULL);
+#endif
+ }
+ zos_remote->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(ZOS_REMOTE *zos_remote, 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 (zos_remote->connected == 0) {
+ rc = zos_remote_connect(zos_remote);
+ if (rc != ICTX_SUCCESS)
+ return rc;
+ }
+
+ /* call LDAP - won't block */
+ rc = ldap_extended_operation(zos_remote->ld, ICTX_OIDAUDITREQUEST,
+ bv, NULL, NULL, &msgId);
+ if (rc == LDAP_SERVER_DOWN) {
+ zos_remote->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 = zos_remote->timeout;
+ t.tv_usec = 0;
+ rc = ldap_result(zos_remote->ld, msgId, 1, &t, &result);
+
+ if (rc == -1) {
+ /* error in ldap operation */
+ ldap_get_option(zos_remote->ld, LDAP_OPT_ERROR_NUMBER, &errcode);
+ switch (errcode) {
+ case LDAP_SERVER_DOWN:
+ /* Connection may have timed out, let's retry */
+ zos_remote->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(zos_remote->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(zos_remote->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 == ZOS_REMOTE_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 == ZOS_REMOTE_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 == ZOS_REMOTE_MAJOR_WARNINGMODE ||
+ response.respMajor == ZOS_REMOTE_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 ZOS_REMOTE_MAJOR_SUCCESS:
+ break;
+ case ZOS_REMOTE_MAJOR_WARNINGMODE:
+ case ZOS_REMOTE_MAJOR_NOTREQ:
+ log_debug("Warning - LDAP extended operation returned '%s' for item %d",
+ zos_remote_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 ZOS_REMOTE_MAJOR_UNDETERMINED:
+ case ZOS_REMOTE_MAJOR_UNAUTHORIZED:
+ case ZOS_REMOTE_MAJOR_RACROUTE:
+ log_err("Error - LDAP extended operation returned '%s' for item %d",
+ zos_remote_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 ZOS_REMOTE_MAJOR_VAL_ERR:
+ case ZOS_REMOTE_MAJOR_ENC_ERR:
+ log_err("Error - LDAP extended operation returned '%s' for item %d",
+ zos_remote_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 ZOS_REMOTE_MAJOR_UNSUF_AUTH:
+ case ZOS_REMOTE_MAJOR_EMPTY:
+ case ZOS_REMOTE_MAJOR_INVALID_VER:
+ case ZOS_REMOTE_MAJOR_INTERNAL_ERR:
+ log_err("Error - LDAP extended operation returned '%s' for item %d",
+ zos_remote_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 z/OS Remote-services server");
+ log_err("Should be %d, got %d", ICTX_REQUESTVER,
+ r->respVersion);
+ rc = ICTX_E_ABORT;
+ goto free_ber;
+ }
+
+ if (r->respMajor == ZOS_REMOTE_MAJOR_SUCCESS ||
+ r->respMajor == ZOS_REMOTE_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 --git a/framework/src/audit/audisp/plugins/zos-remote/zos-remote-ldap.h b/framework/src/audit/audisp/plugins/zos-remote/zos-remote-ldap.h
new file mode 100644
index 00000000..5767b96e
--- /dev/null
+++ b/framework/src/audit/audisp/plugins/zos-remote/zos-remote-ldap.h
@@ -0,0 +1,312 @@
+/***************************************************************************
+ * 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@br.ibm.com> *
+ ***************************************************************************/
+
+#ifndef _ZOS_REMOTE_LDAP_H
+#define _ZOS_REMOTE_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 *
+ * } *
+ * } *
+ ***************************************************************************/
+
+/***************************************************************************
+ * z/OS Remote-services 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 ZOS_REMOTE_EVENT_AUTHENTICATION 0x1
+#define ZOS_REMOTE_EVENT_AUTHORIZATION 0x2
+#define ZOS_REMOTE_EVENT_AUTHORIZATION_MAPPING 0x3
+#define ZOS_REMOTE_EVENT_KEY_MGMT 0x4
+#define ZOS_REMOTE_EVENT_POLICY_MGMT 0x5
+#define ZOS_REMOTE_EVENT_ADMIN_CONFIG 0x6
+#define ZOS_REMOTE_EVENT_ADMIN_ACTION 0x7
+
+/***************************************************************************
+ * Audit Request 'qualifier' field meaning *
+ ***************************************************************************/
+#define ZOS_REMOTE_QUALIF_SUCCESS 0x0
+#define ZOS_REMOTE_QUALIF_INFO 0x1
+#define ZOS_REMOTE_QUALIF_WARN 0x2
+#define ZOS_REMOTE_QUALIF_FAIL 0x3
+
+/***************************************************************************
+ * Relocate types for Audit Request *
+ ***************************************************************************/
+/* SAF identifier for bind user */
+#define ZOS_REMOTE_RELOC_SAF_BIND_USER 100
+
+/* Reguestor's bind user identifier */
+#define ZOS_REMOTE_RELOC_REQ_BIND_USER 101
+
+/* Originating security domain */
+#define ZOS_REMOTE_RELOC_ORIG_SECURITY 102
+
+/* Originating registry / realm */
+#define ZOS_REMOTE_RELOC_ORIG_REALM 103
+
+/* Originating user name */
+#define ZOS_REMOTE_RELOC_ORIG_USER 104
+
+/* Mapped security domain */
+#define ZOS_REMOTE_RELOC_MAPPED_SECURITY 105
+
+/* Mapped registry / realm */
+#define ZOS_REMOTE_RELOC_MAPPED_REALM 106
+
+/* Mapped user name */
+#define ZOS_REMOTE_RELOC_MAPPED_USER 107
+
+/* Operation performed */
+#define ZOS_REMOTE_RELOC_OPERATION 108
+
+/* Mechanism / object name */
+#define ZOS_REMOTE_RELOC_OBJECT 109
+
+/* Method / function used */
+#define ZOS_REMOTE_RELOC_FUNCTION 110
+
+/* Key / certificate name */
+#define ZOS_REMOTE_RELOC_CERTIFICATE 111
+
+/* Caller subject initiating security event */
+#define ZOS_REMOTE_RELOC_INITIATING_EVENT 112
+
+/* Date and time security event occurred */
+#define ZOS_REMOTE_RELOC_TIMESTAMP 113
+
+/* Application specific data. (i.e. Other) */
+#define ZOS_REMOTE_RELOC_OTHER 114
+
+/***************************************************************************
+ * z/OS Remote-services Audit Major return codes *
+ ***************************************************************************/
+#define ZOS_REMOTE_MAJOR_SUCCESS 0
+
+/* Event was logged, with warnings */
+#define ZOS_REMOTE_MAJOR_WARNINGMODE 2
+
+/* No logging required
+ No audit controls are set to require it */
+#define ZOS_REMOTE_MAJOR_NOTREQ 3
+
+/* Class not active/ractlisted,
+ covering profile not found or
+ RACF is not installed */
+#define ZOS_REMOTE_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 ZOS_REMOTE_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 ZOS_REMOTE_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 ZOS_REMOTE_MAJOR_VAL_ERR 16
+
+/* A DER decoding error was encountered in an item.
+ Processing Terminated. Partial results may be returned */
+#define ZOS_REMOTE_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 ZOS_REMOTE_MAJOR_UNSUF_AUTH 24
+
+/* No items are found within the ItemList sequence of the extended
+ operation request, so no response items are returned */
+#define ZOS_REMOTE_MAJOR_EMPTY 28
+
+/* Invalid RequestVersion */
+#define ZOS_REMOTE_MAJOR_INVALID_VER 61
+
+/* An internal error was encountered within the ICTX component */
+#define ZOS_REMOTE_MAJOR_INTERNAL_ERR 100
+
+/***************************************************************************
+ * Some standard sizes for remote audit request items *
+ ***************************************************************************/
+#define ZOS_REMOTE_LINK_VALUE_SIZE 8
+#define ZOS_REMOTE_CLASS_SIZE 8
+#define ZOS_REMOTE_RESOURCE_SIZE 240
+#define ZOS_REMOTE_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 z/OS Remote-services session *
+ ***************************************************************************/
+typedef struct opaque
+{
+ char *server;
+ unsigned int port;
+ char *user;
+ char *password;
+ unsigned int timeout;
+ LDAP *ld;
+ int connected;
+} ZOS_REMOTE;
+
+/***************************************************************************
+ * LDAP XOP operations *
+ ***************************************************************************/
+/*
+ * Initializes z/OS Remote-services (LDAP to ITDS) connection,
+ * binds to ITDS Server using configured RACF ID
+ * Args are:
+ * server, bind user, bind password, server port, timeout
+ * Caller must call zos_remote_destroy() to free memory allocation
+ */
+int zos_remote_init(ZOS_REMOTE *, const char *, int, const char *,
+ const char *, int);
+
+/*
+ * Uninitializes z/OS Remote-services (LDAP) connection
+ */
+void zos_remote_destroy(ZOS_REMOTE *);
+
+/*
+ * sync submit request - possibly reconnect to server
+ * if the connection if found to be dead
+ */
+int submit_request_s(ZOS_REMOTE *, BerElement *);
+
+
+#endif /* _ZOS_REMOTE_LDAP_H */
diff --git a/framework/src/audit/audisp/plugins/zos-remote/zos-remote-log.c b/framework/src/audit/audisp/plugins/zos-remote/zos-remote-log.c
new file mode 100644
index 00000000..a272078e
--- /dev/null
+++ b/framework/src/audit/audisp/plugins/zos-remote/zos-remote-log.c
@@ -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@br.ibm.com> *
+ ***************************************************************************/
+#include "zos-remote-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 --git a/framework/src/audit/audisp/plugins/zos-remote/zos-remote-log.h b/framework/src/audit/audisp/plugins/zos-remote/zos-remote-log.h
new file mode 100644
index 00000000..c5722cbe
--- /dev/null
+++ b/framework/src/audit/audisp/plugins/zos-remote/zos-remote-log.h
@@ -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@br.ibm.com> *
+ ***************************************************************************/
+
+#ifndef _ZOS_REMOTE_LOG_H
+#define _ZOS_REMOTE_LOG_H
+
+#include "zos-remote-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 /* _ZOS_REMOTE_LOG_H */
diff --git a/framework/src/audit/audisp/plugins/zos-remote/zos-remote-plugin.c b/framework/src/audit/audisp/plugins/zos-remote/zos-remote-plugin.c
new file mode 100644
index 00000000..8234a273
--- /dev/null
+++ b/framework/src/audit/audisp/plugins/zos-remote/zos-remote-plugin.c
@@ -0,0 +1,580 @@
+/***************************************************************************
+* 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@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>
+#ifdef HAVE_LIBCAP_NG
+#include <cap-ng.h>
+#endif
+#include "auparse.h"
+#include "zos-remote-log.h"
+#include "zos-remote-ldap.h"
+#include "zos-remote-config.h"
+#include "zos-remote-queue.h"
+
+#define UNUSED(x) (void)(x)
+
+/*
+ * Global vars
+ */
+volatile int stop = 0;
+volatile int hup = 0;
+volatile ZOS_REMOTE zos_remote_inst;
+static plugin_conf_t conf;
+static const char *def_config_file = "/etc/audisp/zos-remote.conf";
+static pthread_t submission_thread;
+pid_t mypid = 0;
+
+/*
+ * SIGTERM handler
+ */
+static void term_handler(int sig)
+{
+ UNUSED(sig);
+ log_info("Got Termination signal - shutting down plugin");
+ stop = 1;
+ nudge_queue();
+}
+
+/*
+ * SIGHUP handler - re-read config, reconnect to ITDS
+ */
+static void hup_handler(int sig)
+{
+ UNUSED(sig);
+ log_info("Got Hangup signal - flushing plugin configuration");
+ hup = 1;
+ nudge_queue();
+}
+
+/*
+ * SIGALRM handler - help force exit when terminating daemon
+ */
+static void alarm_handler(int sig)
+{
+ UNUSED(sig);
+ log_err("Timeout waiting for submission thread - Aborting (some events may have been dropped)");
+ pthread_cancel(submission_thread);
+}
+
+/*
+ * The submission thread
+ * It's job is to dequeue the events from the queue
+ * and sync submit them to ITDS
+ */
+static void *submission_thread_main(void *arg)
+{
+ int rc;
+
+ UNUSED(arg);
+ log_debug("Starting event submission thread");
+
+ rc = zos_remote_init(&zos_remote_inst, conf.server,
+ conf.port, conf.user,
+ conf.password,
+ conf.timeout);
+
+ if (rc != ICTX_SUCCESS) {
+ log_err("Error - Failed to initialize session to z/OS ITDS Server");
+ 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(&zos_remote_inst, ber);
+ if (rc == ICTX_E_FATAL) {
+ log_err("Error - Fatal error in event submission. Aborting");
+ stop = 1;
+ } else if (rc != ICTX_SUCCESS) {
+ log_warn("Warning - 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");
+ zos_remote_destroy(&zos_remote_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[ZOS_REMOTE_LINK_VALUE_SIZE];
+ char logString[ZOS_REMOTE_LOGSTRING_SIZE];
+ unsigned long linkValue_tmp;
+
+ UNUSED(user_data);
+ 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 zos-remote-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 = ZOS_REMOTE_QUALIF_FAIL;
+ else
+ qualifier = ZOS_REMOTE_QUALIF_SUCCESS;
+ } else if (res) {
+ if (strncmp(res, "0", 1) == 0
+ || strncmp(res, "failed", 6) == 0)
+ qualifier = ZOS_REMOTE_QUALIF_FAIL;
+ else
+ qualifier = ZOS_REMOTE_QUALIF_SUCCESS;
+ } else
+ qualifier = ZOS_REMOTE_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, ZOS_REMOTE_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);
+ free((void *)node);
+
+ /*
+ * 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,
+ ZOS_REMOTE_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
+ * SMF type 83, subtype 4 event here
+ */
+ rc |= ber_printf(ber, "i", ZOS_REMOTE_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 ZOS_REMOTE_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 ZOS_REMOTE_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", ZOS_REMOTE_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_interpret_field(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", ZOS_REMOTE_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("Error - Fatal error while encoding request. Aborting");
+ stop = 1;
+}
+
+int main(int argc, char *argv[])
+{
+ int rc;
+ const char *cpath;
+ char buf[1024];
+ struct sigaction sa;
+ sigset_t ss;
+ auparse_state_t *au;
+ ssize_t len;
+
+ mypid = getpid();
+
+ log_info("starting with pid=%d", mypid);
+
+ /*
+ * 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("Using configuration file: %s", cpath);
+ } else {
+ log_err("Error - invalid number of parameters passed. Aborting");
+ return 1;
+ }
+
+ /* initialize record counter */
+ conf.counter = 1;
+
+ /* initialize configuration with default values */
+ plugin_clear_config(&conf);
+
+ /* initialize the submission queue */
+ if (init_queue(conf.q_depth) != 0) {
+ log_err("Error - Can't initialize event queue. Aborting");
+ return -1;
+ }
+
+#ifdef HAVE_LIBCAP_NG
+ // Drop all capabilities
+ capng_clear(CAPNG_SELECT_BOTH);
+ capng_apply(CAPNG_SELECT_BOTH);
+#endif
+
+ /* 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. Aborting",
+ 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 = plugin_load_config(&conf, cpath);
+ if (rc != 0) {
+ log_err("Error - Can't load configuration. Aborting");
+ return -1;
+ }
+ increase_queue_depth(conf.q_depth); /* 1 */
+
+ /* initialize auparse */
+ au = auparse_init(AUSOURCE_FEED, 0); /* 2 */
+ if (au == NULL) {
+ log_err("Error - exiting due to auparse init errors");
+ return -1;
+ }
+
+ /*
+ * 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 - Fatal error while monitoring input: %s. Aborting",
+ 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 - Fatal error while reading input: %s. Aborting",
+ strerror(errno));
+ stop = 1;
+ }
+ else {
+ log_debug("Ignoring read interruption: %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 */
+ plugin_free_config(&conf); /* 1 */
+ }
+ while (hup && stop == 0);
+
+ /* destroy queue before leaving */
+ destroy_queue();
+
+ log_info("Exiting");
+
+ return 0;
+}
diff --git a/framework/src/audit/audisp/plugins/zos-remote/zos-remote-queue.c b/framework/src/audit/audisp/plugins/zos-remote/zos-remote-queue.c
new file mode 100644
index 00000000..8071dca4
--- /dev/null
+++ b/framework/src/audit/audisp/plugins/zos-remote/zos-remote-queue.c
@@ -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@br.ibm.com> *
+ * based on code by Steve Grubb <sgrubb@redhat.com> *
+ ***************************************************************************/
+
+#include "zos-remote-queue.h"
+
+#include <stdlib.h>
+#include <pthread.h>
+#include <syslog.h>
+#include "zos-remote-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 --git a/framework/src/audit/audisp/plugins/zos-remote/zos-remote-queue.h b/framework/src/audit/audisp/plugins/zos-remote/zos-remote-queue.h
new file mode 100644
index 00000000..c653747a
--- /dev/null
+++ b/framework/src/audit/audisp/plugins/zos-remote/zos-remote-queue.h
@@ -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@br.ibm.com> *
+ * based on code by Steve Grubb <sgrubb@redhat.com> *
+ ***************************************************************************/
+
+#ifndef _ZOS_REMOTE_QUEUE_H
+#define _ZOS_REMOTE_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 /* _ZOS_REMOTE_QUEUE_H */
+
diff --git a/framework/src/audit/audisp/plugins/zos-remote/zos-remote.conf b/framework/src/audit/audisp/plugins/zos-remote/zos-remote.conf
new file mode 100644
index 00000000..8cf85f71
--- /dev/null
+++ b/framework/src/audit/audisp/plugins/zos-remote/zos-remote.conf
@@ -0,0 +1,10 @@
+## This is the configuration file for the audispd-zos-remote
+## Audit dispatcher plugin.
+## See zos-remote.conf(5) for more information
+
+server = zos_server.localdomain
+port = 389
+user = RACF_ID
+password = racf_password
+timeout = 15
+q_depth = 64