Home | History | Annotate | Download | only in audit
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     26 
     27 #include <fcntl.h>
     28 #include <libscf.h>
     29 #include <secdb.h>
     30 #include <stdlib.h>
     31 #include <stdio.h>
     32 #include <string.h>
     33 #include <sys/file.h>
     34 #include <sys/types.h>
     35 #include <sys/wait.h>
     36 #include <signal.h>
     37 #include <sys/param.h>
     38 #include <unistd.h>
     39 #include <bsm/audit.h>
     40 #include <bsm/libbsm.h>
     41 #include <locale.h>
     42 #include <audit_sig_infc.h>
     43 #include <zone.h>
     44 
     45 #if !defined(TEXT_DOMAIN)
     46 #define	TEXT_DOMAIN "SUNW_OST_OSCMD"
     47 #endif
     48 
     49 #define	VERIFY -1
     50 
     51 /* GLOBALS */
     52 static char	*auditdatafile = AUDITDATAFILE;
     53 static char	*progname = "audit";
     54 static char	*usage = "audit [-n] | [-s] | [-t] | [-v filepath]";
     55 static int	silent = 0;
     56 static char	*instance_name = "svc:/system/auditd:default";
     57 
     58 static int	get_auditd_pid();
     59 static void	display_smf_error();
     60 
     61 static boolean_t is_audit_control_ok(char *);	/* file validation  */
     62 static boolean_t is_valid_zone(boolean_t);	/* operation ok in this zone? */
     63 static int	start_auditd();			/* start audit daemon */
     64 
     65 /*
     66  * audit() - This program serves as a general administrator's interface to
     67  *	the audit trail.  Only one option is valid at a time.
     68  *
     69  * input:
     70  *	audit -s
     71  *		- signal audit daemon to read audit_control file and
     72  *		  start auditd if needed.
     73  *	audit -n
     74  *		- signal audit daemon to use next audit_control audit directory.
     75  *	audit -t
     76  *		- signal audit daemon to disable auditing.
     77  *	audit -T
     78  *		- signal audit daemon to disable auditing report no errors.
     79  *	audit -v filepath
     80  *		- validate audit_control parameters but use filepath for
     81  *		  the name.  Emit errors or "syntax ok"
     82  *
     83  *
     84  * output:
     85  *
     86  * returns:	0 - command successful
     87  *		>0 - command failed
     88  */
     89 
     90 int
     91 main(int argc, char *argv[])
     92 {
     93 	pid_t pid; /* process id of auditd read from auditdatafile */
     94 	int	sig = 0; /* signal to send auditd */
     95 	char	c;
     96 	char	*first_option;
     97 
     98 	/* Internationalization */
     99 	(void) setlocale(LC_ALL, "");
    100 	(void) textdomain(TEXT_DOMAIN);
    101 
    102 	/* first option required */
    103 	if ((c = getopt(argc, argv, "nstTv:")) == -1) {
    104 		(void) fprintf(stderr, gettext("usage: %s\n"), usage);
    105 		exit(3);
    106 	}
    107 	first_option = optarg;
    108 	/* second or more options not allowed; please pick one */
    109 	if (getopt(argc, argv, "nstTv:") != -1) {
    110 		(void) fprintf(stderr, gettext("usage: %s\n"), usage);
    111 		exit(5);
    112 	}
    113 	switch (c) {
    114 	case 'n':
    115 		if (!is_valid_zone(1))	/* 1 == display error if any */
    116 			exit(10);
    117 
    118 		sig = AU_SIG_NEXT_DIR;
    119 		break;
    120 	case 's':
    121 		if (!is_valid_zone(1))	/* 1 == display error if any */
    122 			exit(10);
    123 		else if (!is_audit_control_ok(NULL))
    124 			exit(7);
    125 
    126 		return (start_auditd());
    127 	case 't':
    128 		if (!is_valid_zone(0))	/* 0 == no error message display */
    129 			exit(10);
    130 		/* use bmsunconv to permanently disable, -t for temporary */
    131 		if (smf_disable_instance(instance_name, SMF_TEMPORARY) != 0) {
    132 			display_smf_error();
    133 			exit(11);
    134 		}
    135 		break;
    136 	case 'T':
    137 		silent = 1;
    138 		if (!is_valid_zone(0))	/* 0 == no error message display */
    139 			exit(10);
    140 
    141 		if (smf_disable_instance(instance_name, SMF_TEMPORARY) != 0) {
    142 			exit(11);
    143 		}
    144 		break;
    145 	case 'v':
    146 		if (is_audit_control_ok(first_option)) {
    147 			(void) fprintf(stderr, gettext("syntax ok\n"));
    148 			exit(0);
    149 		} else {
    150 			exit(8);
    151 		}
    152 		break;
    153 	default:
    154 		(void) fprintf(stderr, gettext("usage: %s\n"), usage);
    155 		exit(6);
    156 	}
    157 
    158 	if (sig != 0) {
    159 		if (get_auditd_pid(&pid) != 0) {
    160 			(void) fprintf(stderr, "%s: %s\n", progname,
    161 			    gettext("can't get process id of auditd from "
    162 			    "audit_data(4)"));
    163 			exit(4);
    164 		}
    165 
    166 		if (kill(pid, sig) != 0) {
    167 			perror(progname);
    168 			(void) fprintf(stderr,
    169 			    gettext("%s: cannot signal auditd\n"), progname);
    170 			exit(1);
    171 		}
    172 	}
    173 	return (0);
    174 }
    175 
    176 
    177 /*
    178  * get_auditd_pid(&pid):
    179  *
    180  * reads PID from audit_data
    181  *
    182  * returns:	0 - successful
    183  *		1 - error
    184  */
    185 
    186 static int
    187 get_auditd_pid(pid_t *p_pid)
    188 {
    189 	FILE	*adp;		/* audit_data file pointer */
    190 	int	retstat;
    191 
    192 	if ((adp = fopen(auditdatafile, "r")) == NULL) {
    193 		if (!silent)
    194 			perror(progname);
    195 		return (1);
    196 	}
    197 	retstat = (fscanf(adp, "%ld", p_pid) != 1);
    198 	(void) fclose(adp);
    199 	return (retstat);
    200 }
    201 
    202 /*
    203  * perform reasonableness check on audit_control or its standin; goal
    204  * is that "audit -s" (1) not crash the system and (2) c2audit/auditd
    205  * actually generates data.
    206  *
    207  * A NULL input is ok -- it is used to tell _openac() to use the
    208  * real audit_control file, not a substitute.
    209  */
    210 #define	TRADITIONAL_MAX	1024
    211 
    212 static boolean_t
    213 is_audit_control_ok(char *filename) {
    214 	char		buf[TRADITIONAL_MAX];
    215 	int		outputs = 0;
    216 	int		state = 1;	/* 1 is ok, 0 is not */
    217 	int		rc;
    218 	int		min;
    219 	kva_t		*kvlist;
    220 	char		*plugin_name;
    221 	char		*plugin_dir;
    222 	au_acinfo_t	*ach;
    223 
    224 	ach = _openac(filename);	/* open audit_control */
    225 	if (ach == NULL) {
    226 		perror(progname);
    227 		exit(9);
    228 	}
    229 	/*
    230 	 * There must be at least one directory or one plugin
    231 	 * defined.
    232 	 */
    233 	if ((rc = _getacdir(ach, buf, TRADITIONAL_MAX)) == 0) {
    234 		outputs++;
    235 	} else if (rc < -1) {	/* -1 is not found, others are errors */
    236 		(void) fprintf(stderr,
    237 			gettext("%s: audit_control \"dir:\" spec invalid\n"),
    238 				progname);
    239 		state = 0;	/* is_not_ok */
    240 	}
    241 
    242 	/*
    243 	 * _getacplug -- all that is of interest is the return code.
    244 	 */
    245 	_rewindac(ach);	/* rewind audit_control */
    246 	while ((rc = _getacplug(ach, &kvlist)) == 0) {
    247 		plugin_name = kva_match(kvlist, "name");
    248 		if (plugin_name == NULL) {
    249 			(void) fprintf(stderr, gettext("%s: audit_control "
    250 			    "\"plugin:\" missing name\n"), progname);
    251 			state = 0;	/* is_not_ok */
    252 		} else {
    253 			if (strcmp(plugin_name, "audit_binfile.so") == 0) {
    254 				plugin_dir = kva_match(kvlist, "p_dir");
    255 				if ((plugin_dir == NULL) && (outputs == 0)) {
    256 					(void) fprintf(stderr,
    257 					    gettext("%s: audit_control "
    258 					    "\"plugin:\" missing p_dir\n"),
    259 					    progname);
    260 					state = 0;	/* is_not_ok */
    261 				} else {
    262 					outputs++;
    263 				}
    264 			}
    265 		}
    266 		_kva_free(kvlist);
    267 	}
    268 	if (rc < -1) {
    269 		(void) fprintf(stderr,
    270 			gettext("%s: audit_control \"plugin:\" spec invalid\n"),
    271 				progname);
    272 		state = 0;	/* is_not_ok */
    273 	}
    274 	if (outputs == 0) {
    275 		(void) fprintf(stderr,
    276 			gettext("%s: audit_control must have either a "
    277 				"valid \"dir:\" entry or a valid \"plugin:\" "
    278 				"entry with \"p_dir:\" specified.\n"),
    279 				progname);
    280 		state = 0;	/* is_not_ok */
    281 	}
    282 	/* minfree is not required */
    283 	_rewindac(ach);
    284 	if ((rc = _getacmin(ach, &min)) < -1) {
    285 		(void) fprintf(stderr,
    286 			gettext(
    287 			    "%s: audit_control \"minfree:\" spec invalid\n"),
    288 			    progname);
    289 		state = 0;	/* is_not_ok */
    290 	}
    291 	/* flags is not required */
    292 	_rewindac(ach);
    293 	if ((rc = _getacflg(ach, buf, TRADITIONAL_MAX)) < -1) {
    294 		(void) fprintf(stderr,
    295 			gettext("%s: audit_control \"flags:\" spec invalid\n"),
    296 				progname);
    297 		state = 0;	/* is_not_ok */
    298 	}
    299 	/* naflags is not required */
    300 	_rewindac(ach);
    301 	if ((rc = _getacna(ach, buf, TRADITIONAL_MAX)) < -1) {
    302 		(void) fprintf(stderr,
    303 			gettext(
    304 			    "%s: audit_control \"naflags:\" spec invalid\n"),
    305 			    progname);
    306 		state = 0;	/* is_not_ok */
    307 	}
    308 	_endac(ach);
    309 	return (state);
    310 }
    311 
    312 /*
    313  * The operations that call this function are only valid in the global
    314  * zone unless the perzone audit policy is set.
    315  *
    316  * "!silent" and "show_err" are slightly different; silent is from
    317  * -T for which no error messages should be displayed and show_err
    318  * applies to more options (including -T)
    319  *
    320  */
    321 
    322 static boolean_t
    323 is_valid_zone(boolean_t show_err)
    324 {
    325 	long	policy;
    326 
    327 	if (auditon(A_GETPOLICY, (char *)&policy, 0) == -1) {
    328 		if (!silent)
    329 			(void) fprintf(stderr, gettext(
    330 			    "%s: Cannot read audit policy:  %s\n"),
    331 			    progname, strerror(errno));
    332 		return (0);
    333 	}
    334 	if (policy & AUDIT_PERZONE)
    335 		return (1);
    336 
    337 	if (getzoneid() != GLOBAL_ZONEID) {
    338 		if (show_err)
    339 			(void) fprintf(stderr,
    340 			    gettext("%s: Not valid in a local zone.\n"),
    341 			    progname);
    342 		return (0);
    343 	} else {
    344 		return (1);
    345 	}
    346 }
    347 
    348 /*
    349  * if auditd isn't running, start it.  Otherwise refresh.
    350  * First check to see if c2audit is loaded via the auditon()
    351  * system call, then check SMF state.
    352  */
    353 static int
    354 start_auditd()
    355 {
    356 	int	audit_state;
    357 	char	*state;
    358 
    359 	if (auditon(A_GETCOND, (caddr_t)&audit_state,
    360 	    sizeof (audit_state)) != 0)
    361 		return (12);
    362 
    363 	if ((state = smf_get_state(instance_name)) == NULL) {
    364 		display_smf_error();
    365 		return (13);
    366 	}
    367 	if (strcmp(SCF_STATE_STRING_ONLINE, state) != 0) {
    368 		if (smf_enable_instance(instance_name, 0) != 0) {
    369 			display_smf_error();
    370 			free(state);
    371 			return (14);
    372 		}
    373 	} else {
    374 		if (smf_refresh_instance(instance_name) != 0) {
    375 			display_smf_error();
    376 			free(state);
    377 			return (15);
    378 		}
    379 	}
    380 	free(state);
    381 	return (0);
    382 }
    383 
    384 static void
    385 display_smf_error()
    386 {
    387 	int	rc = scf_error();
    388 
    389 	switch (rc) {
    390 	case SCF_ERROR_NOT_FOUND:
    391 		(void) fprintf(stderr,
    392 		    "SMF error: \"%s\" not found.\n",
    393 		    instance_name);
    394 		break;
    395 	default:
    396 		(void) fprintf(stderr, "SMF error: %s\n", scf_strerror(rc));
    397 		break;
    398 	}
    399 }
    400