diff options
| author | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
|---|---|---|
| committer | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
| commit | 7c478bd95313f5f23a4c958a745db2134aa03244 (patch) | |
| tree | c871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/cmd/audit | |
| download | illumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz | |
OpenSolaris Launch
Diffstat (limited to 'usr/src/cmd/audit')
| -rw-r--r-- | usr/src/cmd/audit/Makefile | 59 | ||||
| -rw-r--r-- | usr/src/cmd/audit/audit.c | 386 |
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; + } +} |
