summaryrefslogtreecommitdiff
path: root/usr/src/cmd/audit
diff options
context:
space:
mode:
authorstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
committerstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
commit7c478bd95313f5f23a4c958a745db2134aa03244 (patch)
treec871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/cmd/audit
downloadillumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz
OpenSolaris Launch
Diffstat (limited to 'usr/src/cmd/audit')
-rw-r--r--usr/src/cmd/audit/Makefile59
-rw-r--r--usr/src/cmd/audit/audit.c386
2 files changed, 445 insertions, 0 deletions
diff --git a/usr/src/cmd/audit/Makefile b/usr/src/cmd/audit/Makefile
new file mode 100644
index 0000000000..1375d3664c
--- /dev/null
+++ b/usr/src/cmd/audit/Makefile
@@ -0,0 +1,59 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+PROG = audit
+
+include ../Makefile.cmd
+
+TEXT_DOMAIN=SUNW_OST_OSCMD
+POFILE=$(PROG).po
+
+LDLIBS += -lbsm -lsecdb -lscf
+
+AUDITD = ../auditd
+
+OBJS = audit.o
+SRCS = $(OBJS:.o=.c)
+
+CPPFLAGS += -I$(AUDITD)
+
+.KEEP_STATE:
+
+all: $(PROG)
+
+install: all $(ROOTUSRSBINPROG)
+
+_msg: $(POFILE)
+
+catalog: $(POFILE)
+
+clean:
+ rm -f $(OBJS) $(POFILE) $(PROG)
+
+lint: lint_PROG
+
+include ../Makefile.targ
diff --git a/usr/src/cmd/audit/audit.c b/usr/src/cmd/audit/audit.c
new file mode 100644
index 0000000000..1220504dd8
--- /dev/null
+++ b/usr/src/cmd/audit/audit.c
@@ -0,0 +1,386 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <fcntl.h>
+#include <libscf.h>
+#include <secdb.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/file.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <sys/param.h>
+#include <unistd.h>
+#include <bsm/audit.h>
+#include <bsm/libbsm.h>
+#include <locale.h>
+#include <audit_sig_infc.h>
+#include <zone.h>
+
+#if !defined(TEXT_DOMAIN)
+#define TEXT_DOMAIN "SUNW_OST_OSCMD"
+#endif
+
+#define VERIFY -1
+
+/* GLOBALS */
+static char *auditdatafile = AUDITDATAFILE;
+static char *progname = "audit";
+static char *usage = "audit [-n] | [-s] | [-t] | [-v filepath]";
+static int silent = 0;
+static char *instance_name = "svc:/system/auditd:default";
+
+static int get_auditd_pid();
+static void display_smf_error();
+
+static boolean_t is_audit_control_ok(char *); /* file validation */
+static boolean_t is_valid_zone(boolean_t); /* operation ok in this zone? */
+static void start_auditd(); /* start audit daemon */
+
+/*
+ * audit() - This program serves as a general administrator's interface to
+ * the audit trail. Only one option is valid at a time.
+ *
+ * input:
+ * audit -s
+ * - signal audit daemon to read audit_control file and
+ * start auditd if needed.
+ * audit -n
+ * - signal audit daemon to use next audit_control audit directory.
+ * audit -t
+ * - signal audit daemon to disable auditing.
+ * audit -T
+ * - signal audit daemon to disable auditing report no errors.
+ * audit -v filepath
+ * - validate audit_control parameters but use filepath for
+ * the name. Emit errors or "syntax ok"
+ *
+ *
+ * output:
+ *
+ * returns: 0 - command successful
+ * >0 - command failed
+ */
+
+main(int argc, char *argv[])
+{
+ pid_t pid; /* process id of auditd read from auditdatafile */
+ int sig = 0; /* signal to send auditd */
+ char c;
+ char *first_option;
+
+ /* Internationalization */
+ (void) setlocale(LC_ALL, "");
+ (void) textdomain(TEXT_DOMAIN);
+
+ if (getuid() != 0) {
+ (void) fprintf(stderr, gettext("%s: not super-user\n"),
+ progname);
+ exit(2);
+ }
+ /* first option required */
+ if ((c = getopt(argc, argv, "nstTv:")) == -1) {
+ (void) fprintf(stderr, gettext("usage: %s\n"), usage);
+ exit(3);
+ }
+ first_option = optarg;
+ /* second or more options not allowed; please pick one */
+ if (getopt(argc, argv, "nstTv:") != -1) {
+ (void) fprintf(stderr, gettext("usage: %s\n"), usage);
+ exit(5);
+ }
+ switch (c) {
+ case 'n':
+ if (!is_valid_zone(1)) /* 1 == display error if any */
+ exit(10);
+
+ sig = AU_SIG_NEXT_DIR;
+ break;
+ case 's':
+ if (!is_valid_zone(1)) /* 1 == display error if any */
+ exit(10);
+ else if (!is_audit_control_ok(NULL))
+ exit(7);
+
+ start_auditd();
+ break;
+ case 't':
+ if (!is_valid_zone(0)) /* 0 == no error message display */
+ exit(0);
+ /* use bmsunconv to permanently disable, -t for temporary */
+ if (smf_disable_instance(instance_name, SMF_TEMPORARY) != 0)
+ display_smf_error();
+ break;
+ case 'T':
+ if (!is_valid_zone(0)) /* 0 == no error message display */
+ exit(0);
+
+ (void) smf_disable_instance(instance_name, SMF_TEMPORARY);
+ silent = 1;
+ break;
+ case 'v':
+ if (is_audit_control_ok(first_option)) {
+ (void) fprintf(stderr, gettext("syntax ok\n"));
+ exit(0);
+ } else {
+ exit(8);
+ }
+ break;
+ default:
+ (void) fprintf(stderr, gettext("usage: %s\n"), usage);
+ exit(6);
+ }
+
+ if (get_auditd_pid(&pid) != 0) {
+ if (silent) {
+ exit(0);
+ } else {
+ (void) fprintf(stderr, "%s: %s\n", progname, gettext(
+ "can't get process id of auditd from audit_data(4)"));
+ exit(4);
+ }
+ }
+
+ if ((sig != 0) && (kill(pid, sig) != 0)) {
+ if (silent) {
+ exit(0);
+ } else {
+ perror(progname);
+ (void) fprintf(stderr,
+ gettext("%s: cannot signal auditd\n"), progname);
+ exit(1);
+ }
+ }
+ return (0);
+}
+
+
+/*
+ * get_auditd_pid(&pid):
+ *
+ * reads PID from audit_data
+ *
+ * returns: 0 - successful
+ * 1 - error
+ */
+
+static int
+get_auditd_pid(pid_t *p_pid)
+{
+ FILE *adp; /* audit_data file pointer */
+ int retstat;
+
+ if ((adp = fopen(auditdatafile, "r")) == NULL) {
+ if (!silent)
+ perror(progname);
+ return (1);
+ }
+ retstat = (fscanf(adp, "%ld", p_pid) != 1);
+ (void) fclose(adp);
+ return (retstat);
+}
+
+/*
+ * perform reasonableness check on audit_control or its standin; goal
+ * is that "audit -s" (1) not crash the system and (2) c2audit/auditd
+ * actually generates data.
+ *
+ * A NULL input is ok -- it is used to tell _openac() to use the
+ * real audit_control file, not a substitute.
+ */
+#define TRADITIONAL_MAX 1024
+
+static boolean_t
+is_audit_control_ok(char *filename) {
+ char buf[TRADITIONAL_MAX];
+ int outputs = 0;
+ int state = 1; /* 1 is ok, 0 is not */
+ int rc;
+ int min;
+ kva_t *kvlist;
+ char *value;
+ au_acinfo_t *ach;
+
+ ach = _openac(filename); /* open audit_control */
+ if (ach == NULL) {
+ perror(progname);
+ exit(9);
+ }
+ /*
+ * There must be at least one directory or one plugin
+ * defined.
+ */
+ if ((rc = _getacdir(ach, buf, TRADITIONAL_MAX)) == 0) {
+ outputs++;
+ } else if (rc < -1) { /* -1 is not found, others are errors */
+ (void) fprintf(stderr,
+ gettext("%s: audit_control \"dir:\" spec invalid\n"),
+ progname);
+ state = 0; /* is_not_ok */
+ }
+
+ /*
+ * _getacplug -- all that is of interest is the return code.
+ */
+ _rewindac(ach); /* rewind audit_control */
+ if ((rc = _getacplug(ach, &kvlist)) == 0) {
+ value = kva_match(kvlist, "name");
+ if (value == NULL) {
+ (void) fprintf(stderr, gettext("%s: audit_control "
+ "\"plugin:\" missing name\n"), progname);
+ state = 0; /* is_not_ok */
+ }
+ else
+ outputs++;
+
+ _kva_free(kvlist);
+ } else if (rc < -1) {
+ (void) fprintf(stderr,
+ gettext("%s: audit_control \"plugin:\" spec invalid\n"),
+ progname);
+ state = 0; /* is_not_ok */
+ }
+ if (outputs == 0) {
+ (void) fprintf(stderr,
+ gettext("%s: audit_control must have either a "
+ "\"dir:\" or a \"plugin:\" specified.\n"),
+ progname);
+ state = 0; /* is_not_ok */
+ }
+ /* minfree is not required */
+ _rewindac(ach);
+ if ((rc = _getacmin(ach, &min)) < -1) {
+ (void) fprintf(stderr,
+ gettext(
+ "%s: audit_control \"minfree:\" spec invalid\n"),
+ progname);
+ state = 0; /* is_not_ok */
+ }
+ /* flags is not required */
+ _rewindac(ach);
+ if ((rc = _getacflg(ach, buf, TRADITIONAL_MAX)) < -1) {
+ (void) fprintf(stderr,
+ gettext("%s: audit_control \"flags:\" spec invalid\n"),
+ progname);
+ state = 0; /* is_not_ok */
+ }
+ /* naflags is not required */
+ _rewindac(ach);
+ if ((rc = _getacna(ach, buf, TRADITIONAL_MAX)) < -1) {
+ (void) fprintf(stderr,
+ gettext(
+ "%s: audit_control \"naflags:\" spec invalid\n"),
+ progname);
+ state = 0; /* is_not_ok */
+ }
+ _endac(ach);
+ return (state);
+}
+
+/*
+ * The operations that call this function are only valid in the global
+ * zone unless the perzone audit policy is set.
+ *
+ * "!silent" and "show_err" are slightly different; silent is from
+ * -T for which no error messages should be displayed and show_err
+ * applies to more options (including -T)
+ *
+ */
+
+static boolean_t
+is_valid_zone(boolean_t show_err)
+{
+ long policy;
+
+ if (auditon(A_GETPOLICY, (char *)&policy, 0) == -1) {
+ if (!silent)
+ (void) fprintf(stderr, gettext(
+ "%s: Cannot read audit policy: %s\n"),
+ progname, strerror(errno));
+ return (0);
+ }
+ if (policy & AUDIT_PERZONE)
+ return (1);
+
+ if (getzoneid() != GLOBAL_ZONEID) {
+ if (show_err)
+ (void) fprintf(stderr,
+ gettext("%s: Not valid in a local zone.\n"),
+ progname);
+ return (0);
+ } else {
+ return (1);
+ }
+}
+
+/*
+ * if auditd isn't running, start it. Otherwise refresh.
+ * First check to see if c2audit is loaded via the auditon()
+ * system call, then check SMF state.
+ */
+static void
+start_auditd()
+{
+ int audit_state;
+ char *state;
+
+ if (auditon(A_GETCOND, (caddr_t)&audit_state,
+ sizeof (audit_state)) != 0)
+ return;
+
+ if ((state = smf_get_state(instance_name)) == NULL) {
+ display_smf_error();
+ return;
+ }
+ if (strcmp(SCF_STATE_STRING_ONLINE, state) != 0) {
+ if (smf_enable_instance(instance_name, 0) != 0)
+ display_smf_error();
+ } else {
+ if (smf_refresh_instance(instance_name) != 0)
+ display_smf_error();
+ }
+ free(state);
+}
+
+static void
+display_smf_error()
+{
+ int rc = scf_error();
+
+ switch (rc) {
+ case SCF_ERROR_NOT_FOUND:
+ (void) fprintf(stderr,
+ "SMF error: \"%s\" not found.\n",
+ instance_name);
+ break;
+ default:
+ (void) fprintf(stderr, "SMF error %d\n", rc);
+ break;
+ }
+}