xref: /onnv-gate/usr/src/cmd/auditreduce/option.c (revision 11893:ff6e80260186)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51676Sjpk  * Common Development and Distribution License (the "License").
61676Sjpk  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*11893Sgww@eng.sun.com  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate /*
270Sstevel@tonic-gate  * Command line option processing for auditreduce.
280Sstevel@tonic-gate  * The entry point is process_options(), which is called by main().
290Sstevel@tonic-gate  * Process_options() is the only function visible outside this module.
300Sstevel@tonic-gate  */
310Sstevel@tonic-gate 
320Sstevel@tonic-gate #include <locale.h>
330Sstevel@tonic-gate #include <sys/zone.h>	/* for max zonename length */
340Sstevel@tonic-gate #include "auditr.h"
350Sstevel@tonic-gate 
360Sstevel@tonic-gate /*
370Sstevel@tonic-gate  * Object entry.
380Sstevel@tonic-gate  * Maps object strings specified on the command line to a flag
390Sstevel@tonic-gate  * used when searching by object type.
400Sstevel@tonic-gate  */
410Sstevel@tonic-gate 
420Sstevel@tonic-gate struct obj_ent {
430Sstevel@tonic-gate 	char	*obj_str; /* string specified on the command line */
440Sstevel@tonic-gate 	int	obj_flag; /* flag used when searching */
450Sstevel@tonic-gate };
460Sstevel@tonic-gate 
470Sstevel@tonic-gate typedef struct obj_ent obj_ent_t;
480Sstevel@tonic-gate 
490Sstevel@tonic-gate /*
500Sstevel@tonic-gate  * Supports searches by object type.
510Sstevel@tonic-gate  */
520Sstevel@tonic-gate static obj_ent_t obj_tbl[] = {
530Sstevel@tonic-gate 			{ "file", OBJ_PATH },
540Sstevel@tonic-gate 			{ "filegroup", OBJ_FGROUP },
550Sstevel@tonic-gate 			{ "fileowner", OBJ_FOWNER },
561780Sgww 			{ "fmri", OBJ_FMRI },
570Sstevel@tonic-gate 			{ "lp", OBJ_LP   },
580Sstevel@tonic-gate 			{ "msgqid", OBJ_MSG  },
590Sstevel@tonic-gate 			{ "msgqgroup", OBJ_MSGGROUP },
600Sstevel@tonic-gate 			{ "msgqowner", OBJ_MSGOWNER },
610Sstevel@tonic-gate 			{ "path", OBJ_PATH },
620Sstevel@tonic-gate 			{ "pid", OBJ_PROC },
630Sstevel@tonic-gate 			{ "procgroup", OBJ_PGROUP },
640Sstevel@tonic-gate 			{ "procowner", OBJ_POWNER },
650Sstevel@tonic-gate 			{ "semid", OBJ_SEM  },
660Sstevel@tonic-gate 			{ "semgroup", OBJ_SEMGROUP  },
670Sstevel@tonic-gate 			{ "semowner", OBJ_SEMOWNER  },
680Sstevel@tonic-gate 			{ "shmid", OBJ_SHM  },
690Sstevel@tonic-gate 			{ "shmgroup", OBJ_SHMGROUP  },
700Sstevel@tonic-gate 			{ "shmowner", OBJ_SHMOWNER  },
71*11893Sgww@eng.sun.com 			{ "sock", OBJ_SOCK },
72*11893Sgww@eng.sun.com 			{ "user", OBJ_USER } };
730Sstevel@tonic-gate 
740Sstevel@tonic-gate extern int	derive_date(char *, struct tm *);
750Sstevel@tonic-gate extern int	parse_time(char *, int);
760Sstevel@tonic-gate extern char	*re_comp2(char *);
770Sstevel@tonic-gate extern time_t	tm_to_secs(struct tm *);
780Sstevel@tonic-gate 
790Sstevel@tonic-gate static int	a_isnum(char *, int);
800Sstevel@tonic-gate static int	check_file(audit_fcb_t *, int);
810Sstevel@tonic-gate static int	gather_dir(char *);
820Sstevel@tonic-gate static audit_pcb_t *get_next_pcb(char *);
830Sstevel@tonic-gate static obj_ent_t *obj_lkup(char *);
840Sstevel@tonic-gate static int	proc_class(char *);
850Sstevel@tonic-gate static int	proc_date(char *, int);
860Sstevel@tonic-gate static int	proc_file(char *, int);
870Sstevel@tonic-gate static int	process_fileopt(int, char *argv[], int);
880Sstevel@tonic-gate static int	proc_group(char *, gid_t *);
890Sstevel@tonic-gate static int	proc_id(char *, int);
900Sstevel@tonic-gate static int	proc_object(char *);
910Sstevel@tonic-gate static void	proc_pcb(audit_pcb_t *, char *, int);
922101Sgww static int	proc_label(char *);
930Sstevel@tonic-gate static int	proc_subject(char *);
94601Sgww static int	proc_sid(char *);
950Sstevel@tonic-gate static int	proc_type(char *);
960Sstevel@tonic-gate static int	proc_user(char *, uid_t *);
970Sstevel@tonic-gate static int	proc_zonename(char *);
981780Sgww static int	proc_fmri(char *);
990Sstevel@tonic-gate 
1000Sstevel@tonic-gate /*
1010Sstevel@tonic-gate  * .func	process_options - process command line options.
1020Sstevel@tonic-gate  * .desc	Process the user's command line options. These are of two types:
1030Sstevel@tonic-gate  *	single letter flags that are denoted by '-', and filenames. Some
1040Sstevel@tonic-gate  *	of the flags have arguments. Getopt() is used to get the flags.
1050Sstevel@tonic-gate  *	When this is done it calls process_fileopt() to handle any filenames
1060Sstevel@tonic-gate  *	that were there.
1070Sstevel@tonic-gate  * .call	ret = process_options(argc, argv).
1080Sstevel@tonic-gate  * .arg	argc	- the original value.
1090Sstevel@tonic-gate  * .arg	argv	- the original value.
1100Sstevel@tonic-gate  * .ret	0	- no errors detected.
1110Sstevel@tonic-gate  * .ret	-1	- command line error detected (message already printed).
1120Sstevel@tonic-gate  */
1130Sstevel@tonic-gate int
process_options(int argc,char ** argv)1140Sstevel@tonic-gate process_options(int argc, char **argv)
1150Sstevel@tonic-gate {
1160Sstevel@tonic-gate 	int	opt;
1170Sstevel@tonic-gate 	int	error = FALSE;
1180Sstevel@tonic-gate 	int	error_combo = FALSE;
1190Sstevel@tonic-gate 	extern int	optind;		/* in getopt() */
1200Sstevel@tonic-gate 	extern char	*optarg;	/* in getopt() - holds arg to flag */
1210Sstevel@tonic-gate 
122601Sgww 	static char	*options = "ACD:M:NQR:S:VO:"
123601Sgww 	    "a:b:c:d:e:g:j:l:m:o:r:s:t:u:z:";
1240Sstevel@tonic-gate 
1250Sstevel@tonic-gate 	error_str = gettext("general error");
1260Sstevel@tonic-gate 
1270Sstevel@tonic-gate 	zonename = NULL;
1280Sstevel@tonic-gate 	/*
1290Sstevel@tonic-gate 	 * Big switch to process the flags.
1300Sstevel@tonic-gate 	 * Start_over: is for handling the '-' for standard input. Getopt()
1310Sstevel@tonic-gate 	 * doesn't recognize it.
1320Sstevel@tonic-gate 	 */
1330Sstevel@tonic-gate start_over:
1340Sstevel@tonic-gate 	while ((opt = getopt(argc, argv, options)) != EOF) {
1350Sstevel@tonic-gate 		switch (opt) {
1360Sstevel@tonic-gate 		case 'A':		/* all records from the files */
1370Sstevel@tonic-gate 			f_all = TRUE;
1380Sstevel@tonic-gate 			break;
1390Sstevel@tonic-gate 		case 'C':		/* process only completed files */
1400Sstevel@tonic-gate 			f_complete = TRUE;
1410Sstevel@tonic-gate 			break;
1420Sstevel@tonic-gate 		case 'D':		/* delete the files when done */
1430Sstevel@tonic-gate 			/* force 'A' 'C' 'O' to be active */
1440Sstevel@tonic-gate 			f_all = f_complete = TRUE;
1450Sstevel@tonic-gate 			f_outfile = optarg;
1460Sstevel@tonic-gate 			f_delete = TRUE;
1470Sstevel@tonic-gate 			break;
1480Sstevel@tonic-gate 		case 'M':		/* only files from a certain machine */
1490Sstevel@tonic-gate 			f_machine = optarg;
1500Sstevel@tonic-gate 			break;
1510Sstevel@tonic-gate 		case 'N':		/* new object selection mode */
1520Sstevel@tonic-gate 			new_mode = TRUE;
1530Sstevel@tonic-gate 			break;
1540Sstevel@tonic-gate 		case 'Q':		/* no file error reporting */
1550Sstevel@tonic-gate 			f_quiet = TRUE;
1560Sstevel@tonic-gate 			break;
1570Sstevel@tonic-gate 		case 'R':		/* from specified root */
1580Sstevel@tonic-gate 			f_root = optarg;
1590Sstevel@tonic-gate 			break;
1600Sstevel@tonic-gate 		case 'S':		/* from specified server */
1610Sstevel@tonic-gate 			f_server = optarg;
1620Sstevel@tonic-gate 			break;
1630Sstevel@tonic-gate 		case 'V':		/* list all files as they are opened */
1640Sstevel@tonic-gate 			f_verbose = TRUE;
1650Sstevel@tonic-gate 			break;
1660Sstevel@tonic-gate 		case 'O':		/* write to outfile */
1670Sstevel@tonic-gate 			f_outfile = optarg;
1680Sstevel@tonic-gate 			break;
1690Sstevel@tonic-gate 		case 'a':		/* after 'date' */
1700Sstevel@tonic-gate 		case 'b':		/* before 'date' */
1710Sstevel@tonic-gate 		case 'd':		/* from 'day' */
1720Sstevel@tonic-gate 			if (proc_date(optarg, opt))
1730Sstevel@tonic-gate 				error = TRUE;
1740Sstevel@tonic-gate 			break;
1750Sstevel@tonic-gate 		case 'j':		/* subject */
1760Sstevel@tonic-gate 			if (proc_subject(optarg))
1770Sstevel@tonic-gate 				error = TRUE;
1780Sstevel@tonic-gate 			break;
1790Sstevel@tonic-gate 		case 'm':		/* message 'type' */
1800Sstevel@tonic-gate 			if (proc_type(optarg))
1810Sstevel@tonic-gate 				error = TRUE;
1820Sstevel@tonic-gate 			break;
1830Sstevel@tonic-gate 		case 'o':		/* object type */
1840Sstevel@tonic-gate 			if (proc_object(optarg))
1850Sstevel@tonic-gate 				error = TRUE;
1860Sstevel@tonic-gate 			break;
1870Sstevel@tonic-gate 		case 'c':		/* message class */
1880Sstevel@tonic-gate 			if (proc_class(optarg))
1890Sstevel@tonic-gate 				error = TRUE;
1900Sstevel@tonic-gate 			break;
1910Sstevel@tonic-gate 		case 'u':		/* form audit user */
1920Sstevel@tonic-gate 		case 'e':		/* form effective user */
1930Sstevel@tonic-gate 		case 'r':		/* form real user */
1940Sstevel@tonic-gate 		case 'f':		/* form effective group */
1950Sstevel@tonic-gate 		case 'g':		/* form real group */
1960Sstevel@tonic-gate 			if (proc_id(optarg, opt))
1970Sstevel@tonic-gate 				error = TRUE;
1980Sstevel@tonic-gate 			break;
1992101Sgww 		case 'l':		/* TX label range */
2001676Sjpk 			if (!is_system_labeled()) {
2011676Sjpk 				(void) fprintf(stderr,
2021676Sjpk 				    gettext("%s option 'l' requires "
2031676Sjpk 				    "Trusted Extensions.\n"), ar);
2041676Sjpk 				return (-1);
2051676Sjpk 			}
2062101Sgww 			if (proc_label(optarg))
2070Sstevel@tonic-gate 				error = TRUE;
2080Sstevel@tonic-gate 			break;
209601Sgww 		case 's':		/* session ID */
210601Sgww 			if (proc_sid(optarg))
211601Sgww 				error = TRUE;
212601Sgww 			break;
2130Sstevel@tonic-gate 		case 'z':		/* zone name */
2140Sstevel@tonic-gate 			if (proc_zonename(optarg))
2150Sstevel@tonic-gate 				error = TRUE;
2160Sstevel@tonic-gate 			break;
217601Sgww 		case 't':		/* termial ID reserved for later */
2180Sstevel@tonic-gate 		default:
2190Sstevel@tonic-gate 			return (-1);
2200Sstevel@tonic-gate 		}
2210Sstevel@tonic-gate 		if (error) {
2220Sstevel@tonic-gate 			(void) fprintf(stderr,
2237970Spalle@lyckegaard.dk 			    gettext("%s command line error - %s.\n"),
2247970Spalle@lyckegaard.dk 			    ar, error_str);
2250Sstevel@tonic-gate 			return (-1);
2260Sstevel@tonic-gate 		}
2270Sstevel@tonic-gate 	}
2280Sstevel@tonic-gate 	/* catch '-' option for stdin processing - getopt() won't see it */
2290Sstevel@tonic-gate 	if (optind < argc) {
2300Sstevel@tonic-gate 		if (argv[optind][0] == '-' && argv[optind][1] == '\0') {
2310Sstevel@tonic-gate 			optind++;
2320Sstevel@tonic-gate 			f_stdin = TRUE;
2330Sstevel@tonic-gate 			goto start_over;
2340Sstevel@tonic-gate 		}
2350Sstevel@tonic-gate 	}
2360Sstevel@tonic-gate 	/*
2370Sstevel@tonic-gate 	 * Give a default value for 'b' option if not specified.
2380Sstevel@tonic-gate 	 */
2390Sstevel@tonic-gate 	if (m_before == 0)
2400Sstevel@tonic-gate 		m_before = MAXLONG;	/* forever */
2410Sstevel@tonic-gate 	/*
2420Sstevel@tonic-gate 	 * Validate combinations of options.
2430Sstevel@tonic-gate 	 * The following are done:
2440Sstevel@tonic-gate 	 *	1. Can't have 'M' or 'S' or 'R' with filenames.
2450Sstevel@tonic-gate 	 *	2. Can't have an after ('a') time after a before ('b') time.
2460Sstevel@tonic-gate 	 *	3. Delete ('D') must have 'C' and 'A' and 'O' with it.
2470Sstevel@tonic-gate 	 *	4. Input from stdin ('-') can't have filenames too.
2480Sstevel@tonic-gate 	 */
2490Sstevel@tonic-gate 	if ((f_machine || f_server || f_root) && (argc != optind)) {
2500Sstevel@tonic-gate 		error_str = gettext(
2510Sstevel@tonic-gate 		    "no filenames allowed with 'M' or 'S' or 'R' options");
2520Sstevel@tonic-gate 		error_combo = TRUE;
2530Sstevel@tonic-gate 	}
2540Sstevel@tonic-gate 	if (m_after >= m_before) {
2550Sstevel@tonic-gate 		error_str =
2567970Spalle@lyckegaard.dk 		    gettext("'a' parameter must be before 'b' parameter");
2570Sstevel@tonic-gate 		error_combo = TRUE;
2580Sstevel@tonic-gate 	}
2590Sstevel@tonic-gate 	if (f_delete &&
2600Sstevel@tonic-gate 	    (!f_complete || !f_all || !f_outfile)) {
2610Sstevel@tonic-gate 		error_str = gettext(
2620Sstevel@tonic-gate 		    "'C', 'A', and 'O' must be specified with 'D'");
2630Sstevel@tonic-gate 		error_combo = TRUE;
2640Sstevel@tonic-gate 	}
2650Sstevel@tonic-gate 	if (f_stdin && (argc != optind)) {
2660Sstevel@tonic-gate 		error_str = gettext("no filenames allowed with '-' option");
2670Sstevel@tonic-gate 		error_combo = TRUE;
2680Sstevel@tonic-gate 	}
2690Sstevel@tonic-gate 	/*
2700Sstevel@tonic-gate 	 * If error with option combos then print message and exit.
2710Sstevel@tonic-gate 	 * If there was an error with just an option then exit.
2720Sstevel@tonic-gate 	 */
2730Sstevel@tonic-gate 	if (error_combo) {
2740Sstevel@tonic-gate 		(void) fprintf(stderr,
2750Sstevel@tonic-gate 		    gettext("%s command line error - %s.\n"), ar, error_str);
2760Sstevel@tonic-gate 		return (-1);
2770Sstevel@tonic-gate 	}
2780Sstevel@tonic-gate 	if (f_root == NULL)
2790Sstevel@tonic-gate 		f_root = "/etc/security/audit";
2800Sstevel@tonic-gate 	/*
2810Sstevel@tonic-gate 	 * Now handle any filenames included in the command line.
2820Sstevel@tonic-gate 	 */
2830Sstevel@tonic-gate 	return (process_fileopt(argc, argv, optind));
2840Sstevel@tonic-gate }
2850Sstevel@tonic-gate 
2860Sstevel@tonic-gate int
proc_subject(char * optarg)2870Sstevel@tonic-gate proc_subject(char *optarg)
2880Sstevel@tonic-gate {
2890Sstevel@tonic-gate 	if (flags & M_SUBJECT) {
2900Sstevel@tonic-gate 		error_str = gettext("'j' option specified multiple times");
2910Sstevel@tonic-gate 		return (-1);
2920Sstevel@tonic-gate 	}
2930Sstevel@tonic-gate 	flags |= M_SUBJECT;
2940Sstevel@tonic-gate 	subj_id = atol(optarg);
2950Sstevel@tonic-gate 	return (0);
2960Sstevel@tonic-gate }
2970Sstevel@tonic-gate 
298601Sgww int
proc_sid(char * optarg)299601Sgww proc_sid(char *optarg)
300601Sgww {
301601Sgww 	if (flags & M_SID) {
302601Sgww 		error_str = gettext("'s' option specified multiple times");
303601Sgww 		return (-1);
304601Sgww 	}
305601Sgww 	flags |= M_SID;
3067753STon.Nguyen@Sun.COM 	m_sid = (au_asid_t)atol(optarg);
307601Sgww 	return (0);
308601Sgww }
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate int
proc_object(char * optarg)3110Sstevel@tonic-gate proc_object(char *optarg)
3120Sstevel@tonic-gate {
3130Sstevel@tonic-gate 	char	*obj_str;
3140Sstevel@tonic-gate 	char	*obj_val;
3150Sstevel@tonic-gate 	char	*obj_arg;
3160Sstevel@tonic-gate 	int	err;
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate 	obj_ent_t *oep;
3190Sstevel@tonic-gate 	struct hostent *he;
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate 	if (flags & M_OBJECT) {
3220Sstevel@tonic-gate 		error_str = gettext("'o' option specified multiple times");
3230Sstevel@tonic-gate 		return (-1);
3240Sstevel@tonic-gate 	}
3250Sstevel@tonic-gate 	flags |= M_OBJECT;
3260Sstevel@tonic-gate 	if ((obj_arg = strdup(optarg)) == (char *)0)
3270Sstevel@tonic-gate 		return (-1);
3280Sstevel@tonic-gate 	if ((obj_str = strtok(optarg, "=")) == (char *)0 ||
3290Sstevel@tonic-gate 	    (oep = obj_lkup(obj_str)) == (obj_ent_t *)0 ||
3300Sstevel@tonic-gate 	    (obj_val = strtok((char *)0, "=")) == (char *)0) {
3310Sstevel@tonic-gate 		(void) sprintf(errbuf, gettext("invalid object arg (%s)"),
3320Sstevel@tonic-gate 		    obj_arg);
3330Sstevel@tonic-gate 		error_str = errbuf;
3340Sstevel@tonic-gate 		return (-1);
3350Sstevel@tonic-gate 	}
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate 	obj_flag = oep->obj_flag;
3380Sstevel@tonic-gate 
3390Sstevel@tonic-gate 	switch (obj_flag) {
3400Sstevel@tonic-gate 	case OBJ_PATH:
3410Sstevel@tonic-gate 		if ((error_str = re_comp2(obj_val)) != (char *)NULL) {
3420Sstevel@tonic-gate 			return (-1);
3430Sstevel@tonic-gate 		}
3440Sstevel@tonic-gate 		return (0);
3450Sstevel@tonic-gate 		/* NOTREACHED */
3460Sstevel@tonic-gate 	case OBJ_SOCK:
3470Sstevel@tonic-gate 		if (!a_isnum(obj_val, TRUE)) {
3480Sstevel@tonic-gate 			obj_id = atol(obj_val);
3490Sstevel@tonic-gate 			socket_flag = SOCKFLG_PORT;
3500Sstevel@tonic-gate 			return (0);
3510Sstevel@tonic-gate 		}
3520Sstevel@tonic-gate 		if (*obj_val == '0') {
3530Sstevel@tonic-gate 			(void) sscanf(obj_val, "%x", (uint_t *)&obj_id);
3540Sstevel@tonic-gate 			socket_flag = SOCKFLG_PORT;
3550Sstevel@tonic-gate 			return (0);
3560Sstevel@tonic-gate 		}
3570Sstevel@tonic-gate 
3580Sstevel@tonic-gate 		he = getipnodebyname((const void *)obj_val, AF_INET6, 0, &err);
3590Sstevel@tonic-gate 		if (he == 0) {
3600Sstevel@tonic-gate 			he = getipnodebyname((const void *)obj_val, AF_INET,
3610Sstevel@tonic-gate 			    0, &err);
3620Sstevel@tonic-gate 			if (he == 0) {
3630Sstevel@tonic-gate 				(void) sprintf(errbuf,
3640Sstevel@tonic-gate 				    gettext("invalid machine name (%s)"),
3650Sstevel@tonic-gate 				    obj_val);
3660Sstevel@tonic-gate 				error_str = errbuf;
3670Sstevel@tonic-gate 				return (-1);
3680Sstevel@tonic-gate 			}
3690Sstevel@tonic-gate 		}
3700Sstevel@tonic-gate 
3710Sstevel@tonic-gate 		if (he->h_addrtype == AF_INET6) {
3720Sstevel@tonic-gate 			/* LINTED */
3737970Spalle@lyckegaard.dk 			if (IN6_IS_ADDR_V4MAPPED(
3747970Spalle@lyckegaard.dk 			    (in6_addr_t *)he->h_addr_list[0])) {
3750Sstevel@tonic-gate 				/* address is IPv4 (32 bits) */
3768923SMarek.Pospisil@Sun.COM 				(void) memcpy(&obj_id,
3778923SMarek.Pospisil@Sun.COM 				    he->h_addr_list[0] + 12, 4);
3780Sstevel@tonic-gate 				ip_type = AU_IPv4;
3790Sstevel@tonic-gate 			} else {
3800Sstevel@tonic-gate 				(void) memcpy(ip_ipv6, he->h_addr_list[0], 16);
3810Sstevel@tonic-gate 				ip_type = AU_IPv6;
3820Sstevel@tonic-gate 			}
3830Sstevel@tonic-gate 		} else {
3840Sstevel@tonic-gate 			/* address is IPv4 (32 bits) */
3850Sstevel@tonic-gate 			(void) memcpy(&obj_id, he->h_addr_list[0], 4);
3860Sstevel@tonic-gate 			ip_type = AU_IPv4;
3870Sstevel@tonic-gate 		}
3880Sstevel@tonic-gate 
3890Sstevel@tonic-gate 		freehostent(he);
3900Sstevel@tonic-gate 		socket_flag = SOCKFLG_MACHINE;
3910Sstevel@tonic-gate 		return (0);
3920Sstevel@tonic-gate 		break;
3930Sstevel@tonic-gate 	case OBJ_MSG:
3940Sstevel@tonic-gate 	case OBJ_SEM:
3950Sstevel@tonic-gate 	case OBJ_SHM:
3960Sstevel@tonic-gate 	case OBJ_PROC:
3970Sstevel@tonic-gate 		obj_id = atol(obj_val);
3980Sstevel@tonic-gate 		return (0);
3990Sstevel@tonic-gate 		/* NOTREACHED */
4000Sstevel@tonic-gate 	case OBJ_FGROUP:
4010Sstevel@tonic-gate 	case OBJ_MSGGROUP:
4020Sstevel@tonic-gate 	case OBJ_SEMGROUP:
4030Sstevel@tonic-gate 	case OBJ_SHMGROUP:
4040Sstevel@tonic-gate 	case OBJ_PGROUP:
4050Sstevel@tonic-gate 		return (proc_group(obj_val, &obj_group));
4060Sstevel@tonic-gate 		/* NOTREACHED */
4070Sstevel@tonic-gate 	case OBJ_FOWNER:
4080Sstevel@tonic-gate 	case OBJ_MSGOWNER:
4090Sstevel@tonic-gate 	case OBJ_SEMOWNER:
4100Sstevel@tonic-gate 	case OBJ_SHMOWNER:
4110Sstevel@tonic-gate 	case OBJ_POWNER:
4120Sstevel@tonic-gate 		return (proc_user(obj_val, &obj_owner));
4130Sstevel@tonic-gate 		/* NOTREACHED */
4141780Sgww 	case OBJ_FMRI:
4151780Sgww 		return (proc_fmri(obj_val));
4161780Sgww 		/* NOTREACHED */
417*11893Sgww@eng.sun.com 	case OBJ_USER:
418*11893Sgww@eng.sun.com 		return (proc_user(obj_val, &obj_user));
419*11893Sgww@eng.sun.com 		/* NOTREACHED */
4200Sstevel@tonic-gate 	case OBJ_LP: /* lp objects have not yet been defined */
4210Sstevel@tonic-gate 	default: /* impossible */
4220Sstevel@tonic-gate 		(void) sprintf(errbuf, gettext("invalid object type (%s)"),
4230Sstevel@tonic-gate 		    obj_str);
4240Sstevel@tonic-gate 		error_str = errbuf;
4250Sstevel@tonic-gate 		return (-1);
4260Sstevel@tonic-gate 		/* NOTREACHED */
4270Sstevel@tonic-gate 	} /* switch */
4280Sstevel@tonic-gate 	/*NOTREACHED*/
4290Sstevel@tonic-gate }
4300Sstevel@tonic-gate 
4310Sstevel@tonic-gate 
4320Sstevel@tonic-gate obj_ent_t *
obj_lkup(char * obj_str)4330Sstevel@tonic-gate obj_lkup(char *obj_str)
4340Sstevel@tonic-gate {
4350Sstevel@tonic-gate 	int	i;
4360Sstevel@tonic-gate 
4370Sstevel@tonic-gate 	for (i = 0; i < sizeof (obj_tbl) / sizeof (obj_ent_t); i++)
4380Sstevel@tonic-gate 		if (strcmp(obj_str, obj_tbl[i].obj_str) == 0)
4390Sstevel@tonic-gate 			return (&obj_tbl[i]);
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate 	/* not in table */
4427753STon.Nguyen@Sun.COM 	return (NULL);
4430Sstevel@tonic-gate }
4440Sstevel@tonic-gate 
4450Sstevel@tonic-gate 
4460Sstevel@tonic-gate /*
4470Sstevel@tonic-gate  * .func	proc_type - process record type.
4480Sstevel@tonic-gate  * .desc	Process a record type. It is either as a number or a mnemonic.
4490Sstevel@tonic-gate  * .call	ret = proc_type(optstr).
4500Sstevel@tonic-gate  * .arg	optstr	- ptr to name or number.
4510Sstevel@tonic-gate  * .ret	0	- no errors detected.
4520Sstevel@tonic-gate  * .ret	-1	- error detected (error_str contains description).
4530Sstevel@tonic-gate  */
4540Sstevel@tonic-gate int
proc_type(char * optstr)4550Sstevel@tonic-gate proc_type(char *optstr)
4560Sstevel@tonic-gate {
4570Sstevel@tonic-gate 	struct au_event_ent *aep;
4580Sstevel@tonic-gate 
4590Sstevel@tonic-gate 	/*
4600Sstevel@tonic-gate 	 * Either a number or a name.
4610Sstevel@tonic-gate 	 */
4620Sstevel@tonic-gate 
4630Sstevel@tonic-gate 	if (flags & M_TYPE) {
4640Sstevel@tonic-gate 		error_str = gettext("'m' option specified multiple times");
4650Sstevel@tonic-gate 		return (-1);
4660Sstevel@tonic-gate 	}
4670Sstevel@tonic-gate 	flags |= M_TYPE;
4680Sstevel@tonic-gate 	m_type = 0;
4690Sstevel@tonic-gate 	if (a_isnum(optstr, TRUE)) {
4707753STon.Nguyen@Sun.COM 		if ((aep = getauevnam(optstr)) != NULL)
4710Sstevel@tonic-gate 			m_type = aep->ae_number;
4720Sstevel@tonic-gate 	} else {
4730Sstevel@tonic-gate 		if ((aep = getauevnum((au_event_t)atoi(optstr))) !=
4740Sstevel@tonic-gate 		    (struct au_event_ent *)NULL)
4750Sstevel@tonic-gate 			m_type = aep->ae_number;
4760Sstevel@tonic-gate 	}
4770Sstevel@tonic-gate 	if ((m_type == 0)) {
4780Sstevel@tonic-gate 		(void) sprintf(errbuf, gettext("invalid event (%s)"), optstr);
4790Sstevel@tonic-gate 		error_str = errbuf;
4800Sstevel@tonic-gate 		return (-1);
4810Sstevel@tonic-gate 	}
4820Sstevel@tonic-gate 	return (0);
4830Sstevel@tonic-gate }
4840Sstevel@tonic-gate 
4850Sstevel@tonic-gate 
4860Sstevel@tonic-gate /*
4870Sstevel@tonic-gate  * .func	a_isnum - is it a number?
4880Sstevel@tonic-gate  * .desc	Determine if a string is a number or a name.
4890Sstevel@tonic-gate  *	A number may have a leading '+' or '-', but then must be
4900Sstevel@tonic-gate  *	all digits.
4910Sstevel@tonic-gate  * .call	ret = a_isnum(str).
4920Sstevel@tonic-gate  * .arg	str - ptr to the string.
4930Sstevel@tonic-gate  * .arg	leading	- TRUE if leading '+-' allowed.
4940Sstevel@tonic-gate  * .ret	0	- is a number.
4950Sstevel@tonic-gate  * .ret	1	- is not a number.
4960Sstevel@tonic-gate  */
4970Sstevel@tonic-gate int
a_isnum(char * str,int leading)4980Sstevel@tonic-gate a_isnum(char *str, int leading)
4990Sstevel@tonic-gate {
5000Sstevel@tonic-gate 	char	*strs;
5010Sstevel@tonic-gate 
5020Sstevel@tonic-gate 	if ((leading == TRUE) && (*str == '-' || *str == '+'))
5030Sstevel@tonic-gate 		strs = str + 1;
5040Sstevel@tonic-gate 	else
5050Sstevel@tonic-gate 		strs = str;
5060Sstevel@tonic-gate 
5070Sstevel@tonic-gate 	if (strlen(strs) == strspn(strs, "0123456789"))
5080Sstevel@tonic-gate 		return (0);
5090Sstevel@tonic-gate 	else
5100Sstevel@tonic-gate 		return (1);
5110Sstevel@tonic-gate }
5120Sstevel@tonic-gate 
5130Sstevel@tonic-gate 
5140Sstevel@tonic-gate /*
5150Sstevel@tonic-gate  * .func	proc_id	- process user/group id's/
5160Sstevel@tonic-gate  * .desc	Process either a user number/name or group number/name.
5170Sstevel@tonic-gate  *	For names check to see if the name is active in the system
5180Sstevel@tonic-gate  *	to derive the number. If it is not active then fail. For a number
5190Sstevel@tonic-gate  *	also check to see if it is active, but only print a warning if it
5200Sstevel@tonic-gate  *	is not. An administrator may be looking at activity of a 'phantom'
5210Sstevel@tonic-gate  *	user.
5220Sstevel@tonic-gate  * .call	ret = proc_id(optstr, opt).
5230Sstevel@tonic-gate  * .arg	optstr	- ptr to name or number.
5240Sstevel@tonic-gate  * .arg	opt	- 'u' - audit user, 'e' - effective user, 'r' - real user,
5250Sstevel@tonic-gate  *		  'g' - group, 'f' - effective group.
5260Sstevel@tonic-gate  * .ret	0	- no errors detected.
5270Sstevel@tonic-gate  * .ret	-1	- error detected (error_str contains description).
5280Sstevel@tonic-gate  */
5290Sstevel@tonic-gate int
proc_id(char * optstr,int opt)5300Sstevel@tonic-gate proc_id(char *optstr, int opt)
5310Sstevel@tonic-gate {
5320Sstevel@tonic-gate 	switch (opt) {
5330Sstevel@tonic-gate 	case 'e': 		/* effective user id */
5340Sstevel@tonic-gate 		if (flags & M_USERE) {
5350Sstevel@tonic-gate 			error_str = gettext(
5360Sstevel@tonic-gate 			    "'e' option specified multiple times");
5370Sstevel@tonic-gate 			return (-1);
5380Sstevel@tonic-gate 		}
5390Sstevel@tonic-gate 		flags |= M_USERE;
5400Sstevel@tonic-gate 		return (proc_user(optstr, &m_usere));
5410Sstevel@tonic-gate 		/* NOTREACHED */
5420Sstevel@tonic-gate 	case 'f': 		/* effective group id */
5430Sstevel@tonic-gate 		if (flags & M_GROUPE) {
5440Sstevel@tonic-gate 			error_str = gettext(
5450Sstevel@tonic-gate 			    "'f' option specified multiple times");
5460Sstevel@tonic-gate 			return (-1);
5470Sstevel@tonic-gate 		}
5480Sstevel@tonic-gate 		flags |= M_GROUPE;
5490Sstevel@tonic-gate 		return (proc_group(optstr, &m_groupe));
5500Sstevel@tonic-gate 		/* NOTREACHED */
5510Sstevel@tonic-gate 	case 'r': 		/* real user id */
5520Sstevel@tonic-gate 		if (flags & M_USERR) {
5530Sstevel@tonic-gate 			error_str = gettext(
5540Sstevel@tonic-gate 			    "'r' option specified multiple times");
5550Sstevel@tonic-gate 			return (-1);
5560Sstevel@tonic-gate 		}
5570Sstevel@tonic-gate 		flags |= M_USERR;
5580Sstevel@tonic-gate 		return (proc_user(optstr, &m_userr));
5590Sstevel@tonic-gate 		/* NOTREACHED */
5600Sstevel@tonic-gate 	case 'u': 		/* audit user id */
5610Sstevel@tonic-gate 		if (flags & M_USERA) {
5620Sstevel@tonic-gate 			error_str = gettext(
5630Sstevel@tonic-gate 			    "'u' option specified multiple times");
5640Sstevel@tonic-gate 			return (-1);
5650Sstevel@tonic-gate 		}
5660Sstevel@tonic-gate 		flags |= M_USERA;
5670Sstevel@tonic-gate 		return (proc_user(optstr, &m_usera));
5680Sstevel@tonic-gate 		/* NOTREACHED */
5690Sstevel@tonic-gate 	case 'g': 		/* real group id */
5700Sstevel@tonic-gate 		if (flags & M_GROUPR) {
5710Sstevel@tonic-gate 			error_str = gettext(
5720Sstevel@tonic-gate 			    "'g' option specified multiple times");
5730Sstevel@tonic-gate 			return (-1);
5740Sstevel@tonic-gate 		}
5750Sstevel@tonic-gate 		flags |= M_GROUPR;
5760Sstevel@tonic-gate 		return (proc_group(optstr, &m_groupr));
5770Sstevel@tonic-gate 		/* NOTREACHED */
5780Sstevel@tonic-gate 	default: 		/* impossible */
5790Sstevel@tonic-gate 		(void) sprintf(errbuf, gettext("'%c' unknown option"), opt);
5800Sstevel@tonic-gate 		error_str = errbuf;
5810Sstevel@tonic-gate 		return (-1);
5820Sstevel@tonic-gate 		/* NOTREACHED */
5830Sstevel@tonic-gate 	}
5840Sstevel@tonic-gate 	/*NOTREACHED*/
5850Sstevel@tonic-gate }
5860Sstevel@tonic-gate 
5870Sstevel@tonic-gate 
5880Sstevel@tonic-gate int
proc_group(char * optstr,gid_t * gid)5890Sstevel@tonic-gate proc_group(char *optstr, gid_t *gid)
5900Sstevel@tonic-gate {
5910Sstevel@tonic-gate 	struct group *grp;
5920Sstevel@tonic-gate 
5930Sstevel@tonic-gate 	if ((grp = getgrnam(optstr)) == NULL) {
5940Sstevel@tonic-gate 		if (!a_isnum(optstr, TRUE)) {
5950Sstevel@tonic-gate 			*gid = (gid_t)atoi(optstr);
5960Sstevel@tonic-gate 			return (0);
5970Sstevel@tonic-gate 		}
5980Sstevel@tonic-gate 		(void) sprintf(errbuf, gettext("group name invalid (%s)"),
5990Sstevel@tonic-gate 		    optstr);
6000Sstevel@tonic-gate 		error_str = errbuf;
6010Sstevel@tonic-gate 		return (-1);
6020Sstevel@tonic-gate 	}
6030Sstevel@tonic-gate 	*gid = grp->gr_gid;
6040Sstevel@tonic-gate 	return (0);
6050Sstevel@tonic-gate }
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate 
6080Sstevel@tonic-gate int
proc_user(char * optstr,uid_t * uid)6090Sstevel@tonic-gate proc_user(char *optstr, uid_t *uid)
6100Sstevel@tonic-gate {
6110Sstevel@tonic-gate 	struct passwd *usr;
6120Sstevel@tonic-gate 
6130Sstevel@tonic-gate 	if ((usr = getpwnam(optstr)) == NULL) {
6140Sstevel@tonic-gate 		if (!a_isnum(optstr, TRUE)) {
6150Sstevel@tonic-gate 			*uid = (uid_t)atoi(optstr);
6160Sstevel@tonic-gate 			return (0);
6170Sstevel@tonic-gate 		}
6180Sstevel@tonic-gate 		(void) sprintf(errbuf, gettext("user name invalid (%s)"),
6190Sstevel@tonic-gate 		    optstr);
6200Sstevel@tonic-gate 		error_str = errbuf;
6210Sstevel@tonic-gate 		return (-1);
6220Sstevel@tonic-gate 	}
6230Sstevel@tonic-gate 	*uid = usr->pw_uid;
6240Sstevel@tonic-gate 	return (0);
6250Sstevel@tonic-gate }
6260Sstevel@tonic-gate 
6270Sstevel@tonic-gate 
6280Sstevel@tonic-gate /*
6290Sstevel@tonic-gate  * .func proc_date - process date argument.
6300Sstevel@tonic-gate  * .desc Handle a date/time argument. See if the user has erred in combining
6310Sstevel@tonic-gate  *	the types of date arguments. Then parse the string and check for
6320Sstevel@tonic-gate  *	validity of each part.
6330Sstevel@tonic-gate  * .call	ret = proc_date(optstr, opt).
6340Sstevel@tonic-gate  * .arg	optstr	- ptr to date/time string.
6350Sstevel@tonic-gate  * .arg	opt	- 'd' for day, 'a' for after, or 'b' for before.
6360Sstevel@tonic-gate  * .ret	0	- no errors detected.
6370Sstevel@tonic-gate  * .ret	-1	- errors detected (error_str knows what it is).
6380Sstevel@tonic-gate  */
6390Sstevel@tonic-gate int
proc_date(char * optstr,int opt)6400Sstevel@tonic-gate proc_date(char *optstr, int opt)
6410Sstevel@tonic-gate {
6420Sstevel@tonic-gate 	static int	m_day = FALSE;
6430Sstevel@tonic-gate 
6440Sstevel@tonic-gate 	if (opt == 'd') {
6450Sstevel@tonic-gate 		if (m_day == TRUE) {
6460Sstevel@tonic-gate 			error_str = gettext(
6470Sstevel@tonic-gate 			    "'d' option may not be used with 'a' or 'b'");
6480Sstevel@tonic-gate 			return (-1);
6490Sstevel@tonic-gate 		}
6500Sstevel@tonic-gate 		m_day = TRUE;
6510Sstevel@tonic-gate 	}
6520Sstevel@tonic-gate 	if ((opt == 'd') && (m_before || m_after)) {
6530Sstevel@tonic-gate 		error_str = gettext(
6540Sstevel@tonic-gate 		    "'d' option may not be used with 'a' or 'b'");
6550Sstevel@tonic-gate 		return (-1);
6560Sstevel@tonic-gate 	}
6570Sstevel@tonic-gate 	if ((opt == 'a' || opt == 'b') && m_day) {
6580Sstevel@tonic-gate 		error_str = gettext(
6590Sstevel@tonic-gate 		    "'a' or 'b' option may not be used with 'd'");
6600Sstevel@tonic-gate 		return (-1);
6610Sstevel@tonic-gate 	}
6620Sstevel@tonic-gate 	if ((opt == 'a') && (m_after != 0)) {
6630Sstevel@tonic-gate 		error_str = gettext("'a' option specified multiple times");
6640Sstevel@tonic-gate 		return (-1);
6650Sstevel@tonic-gate 	}
6660Sstevel@tonic-gate 	if ((opt == 'b') && (m_before != 0)) {
6670Sstevel@tonic-gate 		error_str = gettext("'b' option specified multiple times");
6680Sstevel@tonic-gate 		return (-1);
6690Sstevel@tonic-gate 	}
6700Sstevel@tonic-gate 	if (parse_time(optstr, opt))
6710Sstevel@tonic-gate 		return (-1);
6720Sstevel@tonic-gate 	return (0);
6730Sstevel@tonic-gate }
6740Sstevel@tonic-gate 
6750Sstevel@tonic-gate 
6760Sstevel@tonic-gate /*
6770Sstevel@tonic-gate  * .func	proc_class - process message class argument.
6780Sstevel@tonic-gate  * .desc	Process class type and see if it is for real.
6790Sstevel@tonic-gate  * .call	ret = proc_class(optstr).
6800Sstevel@tonic-gate  * .arg	optstr	- ptr to class.
6810Sstevel@tonic-gate  * .ret	0	- class has class.
6820Sstevel@tonic-gate  * .ret	-1	- class in no good.
6830Sstevel@tonic-gate  */
6840Sstevel@tonic-gate int
proc_class(char * optstr)6850Sstevel@tonic-gate proc_class(char *optstr)
6860Sstevel@tonic-gate {
6870Sstevel@tonic-gate 	if (flags & M_CLASS) {
6880Sstevel@tonic-gate 		error_str = gettext("'c' option specified multiple times");
6890Sstevel@tonic-gate 		return (-1);
6900Sstevel@tonic-gate 	}
6910Sstevel@tonic-gate 	flags |= M_CLASS;
6920Sstevel@tonic-gate 
6930Sstevel@tonic-gate 	if (getauditflagsbin(optstr, &mask) != 0) {
6940Sstevel@tonic-gate 		(void) sprintf(errbuf, gettext("unknown class (%s)"), optstr);
6950Sstevel@tonic-gate 		error_str = errbuf;
6960Sstevel@tonic-gate 		return (-1);
6970Sstevel@tonic-gate 	}
6980Sstevel@tonic-gate 
6990Sstevel@tonic-gate 	if (mask.am_success != mask.am_failure) {
7000Sstevel@tonic-gate 		flags |= M_SORF;
7010Sstevel@tonic-gate 	}
7020Sstevel@tonic-gate 
7030Sstevel@tonic-gate 	return (0);
7040Sstevel@tonic-gate }
7050Sstevel@tonic-gate 
7060Sstevel@tonic-gate 
7070Sstevel@tonic-gate /*
7080Sstevel@tonic-gate  * .func process_fileopt - process command line file options.
7090Sstevel@tonic-gate  * .desc Process the command line file options and gather the specified files
7100Sstevel@tonic-gate  *	together in file groups based upon file name suffix. The user can
7110Sstevel@tonic-gate  *	specify files explicitly on the command line or via a directory.
7120Sstevel@tonic-gate  *	This is called after the command line flags are processed (as
7130Sstevel@tonic-gate  *	denoted by '-').
7140Sstevel@tonic-gate  * .call	ret = process_fileopt(argc, argv, optindex).
7150Sstevel@tonic-gate  * .arg	argc	- current value of argc.
7160Sstevel@tonic-gate  * .arg	argv	- current value of argv.
7170Sstevel@tonic-gate  * .arg	optindex- current index into argv (as setup by getopt()).
7180Sstevel@tonic-gate  * .ret	0	- no errors detected.
7190Sstevel@tonic-gate  * .ret	-1	- error detected (message already printed).
7200Sstevel@tonic-gate  */
7210Sstevel@tonic-gate int
process_fileopt(int argc,char ** argv,int optindex)7220Sstevel@tonic-gate process_fileopt(int argc, char **argv, int optindex)
7230Sstevel@tonic-gate {
7240Sstevel@tonic-gate 	int	f_mode = FM_ALLDIR;
7250Sstevel@tonic-gate 	char	f_dr[MAXNAMLEN+1];
7260Sstevel@tonic-gate 	char	*f_dir = f_dr;
7270Sstevel@tonic-gate 	char	*fname;
7280Sstevel@tonic-gate 	static char	*std = "standard input";
7290Sstevel@tonic-gate 	audit_fcb_t *fcb;
7300Sstevel@tonic-gate 	DIR * dirp;
7310Sstevel@tonic-gate 	struct dirent *dp;
7320Sstevel@tonic-gate 	audit_pcb_t *pcb;
7330Sstevel@tonic-gate 
7340Sstevel@tonic-gate 	/*
7350Sstevel@tonic-gate 	 * Take input from stdin, not any files.
7360Sstevel@tonic-gate 	 * Use a single fcb to do this.
7370Sstevel@tonic-gate 	 */
7380Sstevel@tonic-gate 	if (f_stdin) {
7390Sstevel@tonic-gate 		fcb = (audit_fcb_t *)a_calloc(1, sizeof (*fcb) + strlen(std));
7400Sstevel@tonic-gate 		(void) strcpy(fcb->fcb_file, std);
7410Sstevel@tonic-gate 		fcb->fcb_suffix = fcb->fcb_name = fcb->fcb_file;
7420Sstevel@tonic-gate 		fcb->fcb_next = NULL;
7430Sstevel@tonic-gate 		fcb->fcb_start = 0;
7440Sstevel@tonic-gate 		fcb->fcb_end = MAXLONG;		/* forever */
7450Sstevel@tonic-gate 		if ((pcb = get_next_pcb((char *)NULL)) == (audit_pcb_t *)NULL)
7460Sstevel@tonic-gate 			return (-1);
7470Sstevel@tonic-gate 		pcb->pcb_suffix = fcb->fcb_file;
7480Sstevel@tonic-gate 		pcb->pcb_dfirst = pcb->pcb_first = fcb;	/* one-item list */
7490Sstevel@tonic-gate 		pcb->pcb_dlast = pcb->pcb_last = fcb;
7500Sstevel@tonic-gate 		pcb->pcb_cur = fcb;
7510Sstevel@tonic-gate 	}
7520Sstevel@tonic-gate 	/*
7530Sstevel@tonic-gate 	 * No files specified on the command line.
7540Sstevel@tonic-gate 	 * Process a directory of files or subdirectories.
7550Sstevel@tonic-gate 	 */
7560Sstevel@tonic-gate 	else if (argc == optindex) {
7570Sstevel@tonic-gate 		/*
7580Sstevel@tonic-gate 		 * A specific server directory was requested.
7590Sstevel@tonic-gate 		 */
7600Sstevel@tonic-gate 		if (f_server) {
7610Sstevel@tonic-gate 			if (strchr(f_server, '/')) {	/* given full path */
7620Sstevel@tonic-gate 				f_dir = f_server;
7630Sstevel@tonic-gate 				f_mode = FM_ALLFILE;	/* all files here */
7640Sstevel@tonic-gate 			} else {		/* directory off audit root */
7650Sstevel@tonic-gate 				f_dir[0] = '\0';
7660Sstevel@tonic-gate 				(void) strcat(f_dir, f_root);
7670Sstevel@tonic-gate 				(void) strcat(f_dir, "/");
7680Sstevel@tonic-gate 				(void) strcat(f_dir, f_server);
7690Sstevel@tonic-gate 				f_mode = FM_ALLFILE;
7700Sstevel@tonic-gate 			}
7710Sstevel@tonic-gate 		}
7720Sstevel@tonic-gate 		/*
7730Sstevel@tonic-gate 		 * Gather all of the files in the directory 'f_dir'.
7740Sstevel@tonic-gate 		 */
7750Sstevel@tonic-gate 		if (f_mode == FM_ALLFILE) {
7760Sstevel@tonic-gate 			if (gather_dir(f_dir)) { /* get those files together */
7770Sstevel@tonic-gate 				return (-1);
7780Sstevel@tonic-gate 			}
7790Sstevel@tonic-gate 		} else {
7800Sstevel@tonic-gate 			/*
7810Sstevel@tonic-gate 			 * Gather all of the files in all of the
7820Sstevel@tonic-gate 			 * directories in 'f_root'.
7830Sstevel@tonic-gate 			 */
7840Sstevel@tonic-gate 			if ((dirp = opendir(f_root)) == NULL) {
7850Sstevel@tonic-gate 				(void) sprintf(errbuf, gettext(
7860Sstevel@tonic-gate 				    "%s can't open directory %s"), ar, f_root);
7870Sstevel@tonic-gate 				perror(errbuf);
7880Sstevel@tonic-gate 				return (-1);
7890Sstevel@tonic-gate 			}
7900Sstevel@tonic-gate 			/* read the directory and process all of the subs */
7910Sstevel@tonic-gate 			for (dp = readdir(dirp);
7920Sstevel@tonic-gate 			    dp != NULL; dp = readdir(dirp)) {
7930Sstevel@tonic-gate 				if (dp->d_name[0] == '.')
7940Sstevel@tonic-gate 					continue;
7950Sstevel@tonic-gate 				f_dir[0] = '\0';
7960Sstevel@tonic-gate 				(void) strcat(f_dir, f_root);
7970Sstevel@tonic-gate 				(void) strcat(f_dir, "/");
7980Sstevel@tonic-gate 				(void) strcat(f_dir, dp->d_name);
7990Sstevel@tonic-gate 				if (gather_dir(f_dir))	/* process a sub */
8000Sstevel@tonic-gate 					return (-1);
8010Sstevel@tonic-gate 			}
8020Sstevel@tonic-gate 			(void) closedir(dirp);
8030Sstevel@tonic-gate 		}
8040Sstevel@tonic-gate 	} else {
8050Sstevel@tonic-gate 		/*
8060Sstevel@tonic-gate 		 * User specified filenames on the comm and line.
8070Sstevel@tonic-gate 		 */
8080Sstevel@tonic-gate 		f_cmdline = TRUE;
8090Sstevel@tonic-gate 		for (; optindex < argc; optindex++) {
8100Sstevel@tonic-gate 			fname = argv[optindex];		/* get a filename */
8110Sstevel@tonic-gate 			if (proc_file(fname, FALSE))
8120Sstevel@tonic-gate 				return (-1);
8130Sstevel@tonic-gate 		}
8140Sstevel@tonic-gate 	}
8150Sstevel@tonic-gate 	return (0);
8160Sstevel@tonic-gate }
8170Sstevel@tonic-gate 
8180Sstevel@tonic-gate 
8190Sstevel@tonic-gate /*
8200Sstevel@tonic-gate  * .func	gather_dir - gather a directory's files together.
8210Sstevel@tonic-gate  * .desc	Process all of the files in a specific directory. The files may
8220Sstevel@tonic-gate  *	be checked for adherence to the file name form at.
8230Sstevel@tonic-gate  *	If the directory can't be opened that is ok - just print
8240Sstevel@tonic-gate  *	a message and continue.
8250Sstevel@tonic-gate  * .call	ret = gather_dir(dir).
8260Sstevel@tonic-gate  * .arg	dir	- ptr to full pathname of directory.
8270Sstevel@tonic-gate  * .ret	0	- no errors detected.
8280Sstevel@tonic-gate  * .ret	-1	- error detected (message already printed).
8290Sstevel@tonic-gate  */
8300Sstevel@tonic-gate int
gather_dir(char * dir)8310Sstevel@tonic-gate gather_dir(char *dir)
8320Sstevel@tonic-gate {
8330Sstevel@tonic-gate 	char	dname[MAXNAMLEN+1];
8340Sstevel@tonic-gate 	char	fname[MAXNAMLEN+1];
8350Sstevel@tonic-gate 	DIR * dirp;
8360Sstevel@tonic-gate 	struct dirent *dp;
8370Sstevel@tonic-gate 
8380Sstevel@tonic-gate 	(void) snprintf(dname, sizeof (dname), "%s/files", dir);
8390Sstevel@tonic-gate 
8400Sstevel@tonic-gate 	if ((dirp = opendir(dname)) == NULL) {
8410Sstevel@tonic-gate 		if (errno != ENOTDIR) {
8420Sstevel@tonic-gate 			(void) sprintf(errbuf,
8430Sstevel@tonic-gate 			    gettext("%s can't open directory - %s"), ar, dname);
8440Sstevel@tonic-gate 			perror(errbuf);
8450Sstevel@tonic-gate 		}
8460Sstevel@tonic-gate 		return (0);
8470Sstevel@tonic-gate 	}
8480Sstevel@tonic-gate 	for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
8490Sstevel@tonic-gate 		if (dp->d_name[0] == '.')	/* can't see hidden files */
8500Sstevel@tonic-gate 			continue;
8510Sstevel@tonic-gate 		fname[0] = '\0';
8520Sstevel@tonic-gate 		(void) strcat(fname, dname);	/* create pathname of file */
8530Sstevel@tonic-gate 		(void) strcat(fname, "/");
8540Sstevel@tonic-gate 		(void) strcat(fname, dp->d_name);
8550Sstevel@tonic-gate 		if (proc_file(fname, TRUE))
8560Sstevel@tonic-gate 			return (-1);
8570Sstevel@tonic-gate 	}
8580Sstevel@tonic-gate 	(void) closedir(dirp);
8590Sstevel@tonic-gate 	return (0);
8600Sstevel@tonic-gate }
8610Sstevel@tonic-gate 
8620Sstevel@tonic-gate 
8630Sstevel@tonic-gate /*
8640Sstevel@tonic-gate  * .func	proc_file - process a single candidate file.
8650Sstevel@tonic-gate  * .desc	Check out a file to see if it should be used in the merge.
8660Sstevel@tonic-gate  *	This includes checking the name (mode is TRUE) against the
8670Sstevel@tonic-gate  *	file format, checking access rights to the file, and thence
8680Sstevel@tonic-gate  *	getting and fcb and installing the fcb into the correct pcb.
8690Sstevel@tonic-gate  *	If the file fails then the fcb is not installed into a pcb
8700Sstevel@tonic-gate  *	and the file dissapears from view.
8710Sstevel@tonic-gate  * .call	proc_file(fname, mode).
8720Sstevel@tonic-gate  * .arg	fname	- ptr to full pathna me of file.
8730Sstevel@tonic-gate  * .arg	mode	- TRUE if checking adherence to file name format.
8740Sstevel@tonic-gate  * .ret	0	- no fatal errors detected.
8750Sstevel@tonic-gate  * .ret	-1	- fatal error detected - quit altogether
8760Sstevel@tonic-gate  *		  (message already printed).
8770Sstevel@tonic-gate  */
8780Sstevel@tonic-gate int
proc_file(char * fname,int mode)8790Sstevel@tonic-gate proc_file(char *fname, int mode)
8800Sstevel@tonic-gate {
8810Sstevel@tonic-gate 	int reject = FALSE;
8820Sstevel@tonic-gate 	size_t len;
8830Sstevel@tonic-gate 	struct stat stat_buf;
8840Sstevel@tonic-gate 	audit_fcb_t *fcb, *fcbp, *fcbprev;
8850Sstevel@tonic-gate 	audit_pcb_t *pcb;
8860Sstevel@tonic-gate 
8870Sstevel@tonic-gate 	/*
8880Sstevel@tonic-gate 	 * See if it is a weird file like a directory or
8890Sstevel@tonic-gate 	 * character special (around here?).
8900Sstevel@tonic-gate 	 */
8910Sstevel@tonic-gate 	if (stat(fname, &stat_buf)) {
8920Sstevel@tonic-gate 		return (0);
8930Sstevel@tonic-gate 	}
894871Scasper 	if (!S_ISREG(stat_buf.st_mode))
8950Sstevel@tonic-gate 		return (0);
8960Sstevel@tonic-gate 	/*
8970Sstevel@tonic-gate 	 * Allocate a new fcb to hold fcb and full filename.
8980Sstevel@tonic-gate 	 */
8990Sstevel@tonic-gate 	len = sizeof (audit_fcb_t) + strlen(fname);
9000Sstevel@tonic-gate 	fcb = (audit_fcb_t *)a_calloc(1, len);
9010Sstevel@tonic-gate 	(void) strcpy(fcb->fcb_file, fname);
9020Sstevel@tonic-gate 	if (check_file(fcb, mode)) { /* check file name */
9030Sstevel@tonic-gate 		if (!f_quiet) {
9040Sstevel@tonic-gate 			(void) fprintf(stderr, "%s %s:\n  %s.\n", ar,
9050Sstevel@tonic-gate 			    error_str, fname);
9060Sstevel@tonic-gate 		}
9070Sstevel@tonic-gate 		reject = TRUE;
9080Sstevel@tonic-gate 	} else {
9090Sstevel@tonic-gate 		/*
9100Sstevel@tonic-gate 		 * Check against file criteria.
9110Sstevel@tonic-gate 		 * Check finish-time here, and start-time later on
9120Sstevel@tonic-gate 		 * while processing.
9130Sstevel@tonic-gate 		 * This is because the start time on a file can be after
9140Sstevel@tonic-gate 		 * the first record(s).
9150Sstevel@tonic-gate 		 */
9160Sstevel@tonic-gate 		if (f_complete && (fcb->fcb_flags & FF_NOTTERM) && !f_cmdline)
9170Sstevel@tonic-gate 			reject = TRUE;
9180Sstevel@tonic-gate 		if (!f_all && (fcb->fcb_end < m_after))
9190Sstevel@tonic-gate 			reject = TRUE;
9200Sstevel@tonic-gate 		if (f_machine) {
9210Sstevel@tonic-gate 			if (strlen(fcb->fcb_suffix) != strlen(f_machine) ||
9220Sstevel@tonic-gate 			    (strcmp(fcb->fcb_suffix, f_machine) != 0)) {
9230Sstevel@tonic-gate 				reject = TRUE;
9240Sstevel@tonic-gate 			}
9250Sstevel@tonic-gate 		}
9260Sstevel@tonic-gate 	}
9270Sstevel@tonic-gate 	if (reject == FALSE) {
9280Sstevel@tonic-gate 		filenum++;	/* count of total files to be processed */
9290Sstevel@tonic-gate 		fcb->fcb_next = NULL;
9300Sstevel@tonic-gate 		if ((pcb = get_next_pcb(fcb->fcb_suffix)) == NULL) {
9310Sstevel@tonic-gate 			return (-1);
9320Sstevel@tonic-gate 		}
9330Sstevel@tonic-gate 		/* Place FCB into the PCB in order - oldest first.  */
9340Sstevel@tonic-gate 		fcbp = pcb->pcb_first;
9350Sstevel@tonic-gate 		fcbprev = NULL;
9360Sstevel@tonic-gate 		while (fcbp != NULL) {
9370Sstevel@tonic-gate 			if (fcb->fcb_start < fcbp->fcb_start) {
9380Sstevel@tonic-gate 				if (fcbprev)
9390Sstevel@tonic-gate 					fcbprev->fcb_next = fcb;
9400Sstevel@tonic-gate 				else
9410Sstevel@tonic-gate 					pcb->pcb_dfirst = pcb->pcb_first = fcb;
9420Sstevel@tonic-gate 				fcb->fcb_next = fcbp;
9430Sstevel@tonic-gate 				break;
9440Sstevel@tonic-gate 			}
9450Sstevel@tonic-gate 			fcbprev = fcbp;
9460Sstevel@tonic-gate 			fcbp = fcbp->fcb_next;
9470Sstevel@tonic-gate 		}
9480Sstevel@tonic-gate 		/* younger than all || empty list */
9490Sstevel@tonic-gate 		if (!fcb->fcb_next) {
9500Sstevel@tonic-gate 			if (pcb->pcb_first == NULL)
9510Sstevel@tonic-gate 				pcb->pcb_dfirst = pcb->pcb_first = fcb;
9520Sstevel@tonic-gate 			pcb->pcb_dlast = pcb->pcb_last = fcb;
9530Sstevel@tonic-gate 			if (fcbprev)
9540Sstevel@tonic-gate 				fcbprev->fcb_next = fcb;
9550Sstevel@tonic-gate 		}
9560Sstevel@tonic-gate 	} else {
9570Sstevel@tonic-gate 		free((char *)fcb);	/* rejected */
9580Sstevel@tonic-gate 	}
9590Sstevel@tonic-gate 	return (0);
9600Sstevel@tonic-gate }
9610Sstevel@tonic-gate 
9620Sstevel@tonic-gate 
9630Sstevel@tonic-gate /*
9640Sstevel@tonic-gate  * .func	check_file - check filename and setup fcb.
9650Sstevel@tonic-gate  * .desc	Check adherence to the file format (do_check is TRUE) and setup
9660Sstevel@tonic-gate  *	the fcb with useful information.
9670Sstevel@tonic-gate  *	filename format: yyyymmddhhmmss.yyyymmddhhmmss.suffix
9680Sstevel@tonic-gate  *			 yyyymmddhhmmss.not_terminated.suffix
9690Sstevel@tonic-gate  *	If do_check is FALSE then still see if the filename does confirm
9700Sstevel@tonic-gate  *	to the format. If it does then extract useful information from
9710Sstevel@tonic-gate  *	it (start time and end time).  But if it doesn't then don't print
9720Sstevel@tonic-gate  *	any error messages.
9730Sstevel@tonic-gate  * .call	ret = check_file(fcb, do_check).
9740Sstevel@tonic-gate  * .arg	fcb	- ptr to fcb that holds the file.
9750Sstevel@tonic-gate  * .arg	do_check - if TRUE do check adherence to file format.
9760Sstevel@tonic-gate  * .ret	0	- no errors detected.
9770Sstevel@tonic-gate  * .ret	-1	- file failed somehow (error_str tells why).
9780Sstevel@tonic-gate  */
9790Sstevel@tonic-gate int
check_file(audit_fcb_t * fcb,int do_check)9800Sstevel@tonic-gate check_file(audit_fcb_t *fcb, int do_check)
9810Sstevel@tonic-gate {
9820Sstevel@tonic-gate 	int	ret;
9830Sstevel@tonic-gate 	char	*namep, *slp;
9840Sstevel@tonic-gate 	char	errb[256];		/* build error message */
9850Sstevel@tonic-gate 	struct tm tme;
9860Sstevel@tonic-gate 
9870Sstevel@tonic-gate 	errb[0] = '\0';
9880Sstevel@tonic-gate 	/* get just the filename */
9890Sstevel@tonic-gate 	for (slp = namep = fcb->fcb_file; *namep; namep++) {
9900Sstevel@tonic-gate 		if (*namep == '/')
9910Sstevel@tonic-gate 			slp = namep + 1; /* slp -> the filename itself */
9920Sstevel@tonic-gate 	}
9930Sstevel@tonic-gate 	if (do_check == FALSE) {
9940Sstevel@tonic-gate 		fcb->fcb_end = MAXLONG;		/* forever */
9950Sstevel@tonic-gate 		fcb->fcb_suffix = NULL;
9960Sstevel@tonic-gate 		fcb->fcb_name = slp;
9970Sstevel@tonic-gate 		ret = 0;
9980Sstevel@tonic-gate 	} else {
9990Sstevel@tonic-gate 		ret = -1;
10000Sstevel@tonic-gate 	}
10010Sstevel@tonic-gate 	if ((int)strlen(slp) < 31) {
10020Sstevel@tonic-gate 		(void) sprintf(errbuf, gettext("filename too short (%d)"),
10030Sstevel@tonic-gate 		    strlen(slp));
10040Sstevel@tonic-gate 		error_str = errbuf;
10050Sstevel@tonic-gate 		return (ret);
10060Sstevel@tonic-gate 	}
10070Sstevel@tonic-gate 	/*
10080Sstevel@tonic-gate 	 * Get working copy of filename.
10090Sstevel@tonic-gate 	 */
10100Sstevel@tonic-gate 	namep = (char *)a_calloc(1, strlen(slp) + 1);
10110Sstevel@tonic-gate 	(void) strcpy(namep, slp);
10120Sstevel@tonic-gate 	if (namep[14] != '.' || namep[29] != '.') {
10130Sstevel@tonic-gate 		(void) sprintf(errbuf,
10140Sstevel@tonic-gate 		    gettext("invalid filename format (%c or %c)"), namep[14],
10150Sstevel@tonic-gate 		    namep[29]);
10160Sstevel@tonic-gate 		error_str = errbuf;
10170Sstevel@tonic-gate 		free(namep);
10180Sstevel@tonic-gate 		return (ret);
10190Sstevel@tonic-gate 	}
10200Sstevel@tonic-gate 	namep[14] = '\0';			/* mark off start time */
10210Sstevel@tonic-gate 	namep[29] = '\0';			/* mark off finish time */
10220Sstevel@tonic-gate 	if (derive_date(namep, &tme)) {
10230Sstevel@tonic-gate 		(void) strcat(errb, gettext("starting time-stamp invalid - "));
10240Sstevel@tonic-gate 		(void) strcat(errb, error_str);
10250Sstevel@tonic-gate 		(void) strcpy(errbuf, errb);
10260Sstevel@tonic-gate 		error_str = errbuf;
10270Sstevel@tonic-gate 		free(namep);
10280Sstevel@tonic-gate 		return (ret);
10290Sstevel@tonic-gate 	}
10300Sstevel@tonic-gate 	/*
10310Sstevel@tonic-gate 	 * Keep start time from filename. Use it to order files in
10320Sstevel@tonic-gate 	 * the file list. Later we will update this when we read
10330Sstevel@tonic-gate 	 * the first record from the file.
10340Sstevel@tonic-gate 	 */
10350Sstevel@tonic-gate 	fcb->fcb_start = tm_to_secs(&tme);
10360Sstevel@tonic-gate 
10370Sstevel@tonic-gate 	if (strcmp(&namep[15], "not_terminated") == 0) {
10380Sstevel@tonic-gate 		fcb->fcb_end = MAXLONG;		/* forever */
10390Sstevel@tonic-gate 		/*
10400Sstevel@tonic-gate 		 * Only treat a 'not_terminated' file as such if
10410Sstevel@tonic-gate 		 * it is not on the command line.
10420Sstevel@tonic-gate 		 */
10430Sstevel@tonic-gate 		if (do_check == TRUE)
10440Sstevel@tonic-gate 			fcb->fcb_flags |= FF_NOTTERM;
10450Sstevel@tonic-gate 	} else if (derive_date(&namep[15], &tme)) {
10460Sstevel@tonic-gate 		(void) strcat(errb, gettext("ending time-stamp invalid - "));
10470Sstevel@tonic-gate 		(void) strcat(errb, error_str);
10480Sstevel@tonic-gate 		(void) strcpy(errbuf, errb);
10490Sstevel@tonic-gate 		error_str = errbuf;
10500Sstevel@tonic-gate 		free(namep);
10510Sstevel@tonic-gate 		return (ret);
10520Sstevel@tonic-gate 	} else {
10530Sstevel@tonic-gate 		fcb->fcb_end = tm_to_secs(&tme);
10540Sstevel@tonic-gate 	}
10550Sstevel@tonic-gate 	fcb->fcb_name = slp;
10560Sstevel@tonic-gate 	fcb->fcb_suffix = &slp[30];
10570Sstevel@tonic-gate 	free(namep);
10580Sstevel@tonic-gate 	return (0);
10590Sstevel@tonic-gate }
10600Sstevel@tonic-gate 
10610Sstevel@tonic-gate 
10620Sstevel@tonic-gate /*
10630Sstevel@tonic-gate  * .func get_next_pcb - get a pcb to use.
10640Sstevel@tonic-gate  * .desc	The pcb's in the array audit_pcbs are used to hold single file
10650Sstevel@tonic-gate  *	groups in the form of a linked list. Each pcb holds files that
10660Sstevel@tonic-gate  *	are tied together by a common suffix in the file name. Here we
10670Sstevel@tonic-gate  *	get either 1. the existing pcb holding a specified sufix or
10680Sstevel@tonic-gate  *	2. a new pcb if we can't find an existing one.
10690Sstevel@tonic-gate  * .call	pcb = get_next_pcb(suffix).
10700Sstevel@tonic-gate  * .arg	suffix	- ptr to suffix we are seeking.
10710Sstevel@tonic-gate  * .ret	pcb	- ptr to pcb that hold s the sought suffix.
10720Sstevel@tonic-gate  * .ret	NULL- serious failure in memory allocation. Quit processing.
10730Sstevel@tonic-gate  */
10740Sstevel@tonic-gate audit_pcb_t *
get_next_pcb(char * suffix)10750Sstevel@tonic-gate get_next_pcb(char *suffix)
10760Sstevel@tonic-gate {
10770Sstevel@tonic-gate 	int	i = 0;
10780Sstevel@tonic-gate 	int	zerosize;
10790Sstevel@tonic-gate 	unsigned int	size;
10800Sstevel@tonic-gate 	audit_pcb_t *pcb;
10810Sstevel@tonic-gate 
10820Sstevel@tonic-gate 	/* Search through (maybe) entire array. */
10830Sstevel@tonic-gate 	while (i < pcbsize) {
10840Sstevel@tonic-gate 		pcb = &audit_pcbs[i++];
10850Sstevel@tonic-gate 		if (pcb->pcb_first == NULL) {
10860Sstevel@tonic-gate 			proc_pcb(pcb, suffix, i);
10870Sstevel@tonic-gate 			return (pcb);	/* came to an unused one */
10880Sstevel@tonic-gate 		}
10890Sstevel@tonic-gate 		if (suffix) {
10900Sstevel@tonic-gate 			if (strcmp(pcb->pcb_suffix, suffix) == 0)
10910Sstevel@tonic-gate 				return (pcb);	/* matched one with suffix */
10920Sstevel@tonic-gate 		}
10930Sstevel@tonic-gate 	}
10940Sstevel@tonic-gate 	/*
10950Sstevel@tonic-gate 	 * Uh-oh, the entire array is used and we haven't gotten one yet.
10960Sstevel@tonic-gate 	 * Allocate a bigger array.
10970Sstevel@tonic-gate 	 */
10980Sstevel@tonic-gate 	pcbsize += PCB_INC;
10990Sstevel@tonic-gate 	size = pcbsize * sizeof (audit_pcb_t);
11000Sstevel@tonic-gate 	zerosize = size - ((pcbsize - PCB_INC) * sizeof (audit_pcb_t));
11010Sstevel@tonic-gate 	if ((audit_pcbs = (audit_pcb_t *)realloc((char *)audit_pcbs, size)) ==
11020Sstevel@tonic-gate 	    NULL) {
11030Sstevel@tonic-gate 		(void) sprintf(errbuf,
11040Sstevel@tonic-gate 		    gettext("%s memory reallocation failed (%d bytes)"), ar,
11050Sstevel@tonic-gate 		    size);
11060Sstevel@tonic-gate 		perror(errbuf);
11070Sstevel@tonic-gate 		audit_stats();		/* give user statistics on usage */
11080Sstevel@tonic-gate 		return (NULL);		/* really bad thing to have happen */
11090Sstevel@tonic-gate 	}
11100Sstevel@tonic-gate 	/*
11110Sstevel@tonic-gate 	 * Don't know if realloc clears the new memory like calloc would.
11120Sstevel@tonic-gate 	 */
11130Sstevel@tonic-gate 	(void) memset((void *) & audit_pcbs[pcbsize-PCB_INC], 0,
11140Sstevel@tonic-gate 	    (size_t)zerosize);
11150Sstevel@tonic-gate 	pcb = &audit_pcbs[pcbsize-PCB_INC];	/* allocate the first new one */
11160Sstevel@tonic-gate 	proc_pcb(pcb, suffix, pcbsize - PCB_INC);
11170Sstevel@tonic-gate 	return (pcb);
11180Sstevel@tonic-gate }
11190Sstevel@tonic-gate 
11200Sstevel@tonic-gate 
11210Sstevel@tonic-gate /*
11220Sstevel@tonic-gate  * .func proc_pcb - process pcb.
11230Sstevel@tonic-gate  * .desc	Common pcb processing for above routine.
11240Sstevel@tonic-gate  * .call	proc_pcb(pcb, suffix, i).
11250Sstevel@tonic-gate  * .arg	pcb	- ptr to pcb.
11260Sstevel@tonic-gate  * .arg	suffix	- prt to suffix tha t ties this group together.
11270Sstevel@tonic-gate  * .arg	i	- index into audit_pcbs[ ].
11280Sstevel@tonic-gate  * .ret	void.
11290Sstevel@tonic-gate  */
11300Sstevel@tonic-gate void
proc_pcb(audit_pcb_t * pcb,char * suffix,int i)11310Sstevel@tonic-gate proc_pcb(audit_pcb_t *pcb, char *suffix, int i)
11320Sstevel@tonic-gate {
11330Sstevel@tonic-gate 	if (suffix)
11340Sstevel@tonic-gate 		pcb->pcb_suffix = suffix;
11350Sstevel@tonic-gate 	pcbnum++;	/* one more pcb in use */
11360Sstevel@tonic-gate 	pcb->pcb_size = AUDITBUFSIZE;
11370Sstevel@tonic-gate 	pcb->pcb_rec = (char *)a_calloc(1, AUDITBUFSIZE);
11380Sstevel@tonic-gate 	pcb->pcb_time = -1;
11397970Spalle@lyckegaard.dk 	pcb->pcb_flags |= PF_USEFILE;	/* note this one controls files */
11400Sstevel@tonic-gate 	pcb->pcb_procno = i;	/* save index into audit_pcbs [] for id */
11410Sstevel@tonic-gate }
11420Sstevel@tonic-gate 
11430Sstevel@tonic-gate 
11440Sstevel@tonic-gate /*
11452101Sgww  * .func	proc_label - process label range argument.
11462101Sgww  * .desc	Parse label range lower-bound[;upper-bound]
11472101Sgww  * .call	ret = proc_label(optstr).
11480Sstevel@tonic-gate  * .arg	opstr	- ptr to label range string
11490Sstevel@tonic-gate  * .ret 0	- no errors detected.
11502101Sgww  * .ret -1	- errors detected (error_str set).
11510Sstevel@tonic-gate  */
11520Sstevel@tonic-gate 
11530Sstevel@tonic-gate int
proc_label(char * optstr)11542101Sgww proc_label(char *optstr)
11550Sstevel@tonic-gate {
11560Sstevel@tonic-gate 	char	*p;
11570Sstevel@tonic-gate 	int	error;
11580Sstevel@tonic-gate 
1159601Sgww 	if (flags & M_LABEL) {
1160601Sgww 		error_str = gettext("'l' option specified multiple times");
11610Sstevel@tonic-gate 		return (-1);
11620Sstevel@tonic-gate 	}
11631676Sjpk 	flags |= M_LABEL;
11640Sstevel@tonic-gate 
11651676Sjpk 	if ((m_label = malloc(sizeof (m_range_t))) == NULL) {
11661676Sjpk 		return (-1);
11671676Sjpk 	}
11681676Sjpk 	m_label->lower_bound = NULL;
11691676Sjpk 	m_label->upper_bound = NULL;
11701676Sjpk 
11711676Sjpk 	p = strchr(optstr, ';');
11720Sstevel@tonic-gate 	if (p == NULL) {
11730Sstevel@tonic-gate 		/* exact label match, lower and upper range bounds the same */
11741676Sjpk 		if (str_to_label(optstr, &m_label->lower_bound, MAC_LABEL,
11751676Sjpk 		    L_NO_CORRECTION, &error) == -1) {
11760Sstevel@tonic-gate 			(void) sprintf(errbuf,
11770Sstevel@tonic-gate 			    gettext("invalid sensitivity label (%s) err %d"),
11780Sstevel@tonic-gate 			    optstr, error);
11790Sstevel@tonic-gate 			error_str = errbuf;
11801676Sjpk 			goto errout;
11810Sstevel@tonic-gate 		}
11821676Sjpk 		m_label->upper_bound = m_label->lower_bound;
11830Sstevel@tonic-gate 		return (0);
11840Sstevel@tonic-gate 	}
11850Sstevel@tonic-gate 	if (p == optstr) {
11860Sstevel@tonic-gate 		/* lower bound is not specified .. default is admin_low */
11871676Sjpk 		if (str_to_label(ADMIN_LOW, &m_label->lower_bound, MAC_LABEL,
11881676Sjpk 		    L_NO_CORRECTION, &error) == -1) {
11892101Sgww 			goto errout;
11900Sstevel@tonic-gate 		}
11911676Sjpk 
11921676Sjpk 		p++;
11931676Sjpk 		if (*p == '\0') {
11941676Sjpk 			/* upper bound not specified .. default is admin_high */
11951676Sjpk 			if (str_to_label(ADMIN_HIGH, &m_label->upper_bound,
11961676Sjpk 			    MAC_LABEL, L_NO_CORRECTION, &error) == -1) {
11972101Sgww 				goto errout;
11981676Sjpk 			}
11991676Sjpk 		} else {
12001676Sjpk 			if (str_to_label(p, &m_label->upper_bound, MAC_LABEL,
12011676Sjpk 			    L_NO_CORRECTION, &error) == -1) {
12021676Sjpk 				(void) sprintf(errbuf, gettext(
12031676Sjpk 				    "invalid sensitivity label (%s) err %d"),
12041676Sjpk 				    p, error);
12051676Sjpk 				error_str = errbuf;
12061676Sjpk 				goto errout;
12071676Sjpk 			}
12081676Sjpk 		}
12090Sstevel@tonic-gate 		return (0);
12100Sstevel@tonic-gate 	}
12110Sstevel@tonic-gate 	*p++ = '\0';
12121676Sjpk 	if (str_to_label(optstr, &m_label->lower_bound, MAC_LABEL,
12131676Sjpk 	    L_NO_CORRECTION, &error) == -1) {
12140Sstevel@tonic-gate 		(void) sprintf(errbuf,
12150Sstevel@tonic-gate 		    gettext("invalid sensitivity label (%s) err %d"), optstr,
12160Sstevel@tonic-gate 		    error);
12170Sstevel@tonic-gate 		error_str = errbuf;
12181676Sjpk 		goto errout;
12190Sstevel@tonic-gate 	}
12201676Sjpk 	if (*p == '\0') {
12210Sstevel@tonic-gate 		/* upper bound is not specified .. default is admin_high */
12221676Sjpk 		if (str_to_label(ADMIN_HIGH, &m_label->upper_bound,
12231676Sjpk 		    MAC_LABEL, L_NO_CORRECTION, &error) == -1) {
12242101Sgww 			goto errout;
12251676Sjpk 		}
12261676Sjpk 	} else {
12271676Sjpk 		if (str_to_label(p, &m_label->upper_bound, MAC_LABEL,
12281676Sjpk 		    L_NO_CORRECTION, &error) == -1) {
12290Sstevel@tonic-gate 			(void) sprintf(errbuf,
12300Sstevel@tonic-gate 			    gettext("invalid sensitivity label (%s) err %d"),
12310Sstevel@tonic-gate 			    p, error);
12320Sstevel@tonic-gate 			error_str = errbuf;
12331676Sjpk 			goto errout;
12340Sstevel@tonic-gate 		}
12350Sstevel@tonic-gate 	}
12360Sstevel@tonic-gate 	/* make sure that upper bound dominates the lower bound */
12371676Sjpk 	if (!bldominates(m_label->upper_bound, m_label->lower_bound)) {
12381676Sjpk 		*--p = ';';
12390Sstevel@tonic-gate 		(void) sprintf(errbuf,
12400Sstevel@tonic-gate 		    gettext("invalid sensitivity label range (%s)"), optstr);
12410Sstevel@tonic-gate 		error_str = errbuf;
12421676Sjpk 		goto errout;
12430Sstevel@tonic-gate 	}
12440Sstevel@tonic-gate 	return (0);
12451676Sjpk 
12461676Sjpk errout:
12471676Sjpk 	m_label_free(m_label->upper_bound);
12481676Sjpk 	m_label_free(m_label->lower_bound);
12491676Sjpk 	free(m_label);
12501676Sjpk 
12511676Sjpk 	return (-1);
12520Sstevel@tonic-gate }
12530Sstevel@tonic-gate 
12540Sstevel@tonic-gate /*
12550Sstevel@tonic-gate  * proc_zonename - pick up zone name.
12560Sstevel@tonic-gate  *
12570Sstevel@tonic-gate  * all non-empty and not-too-long strings are valid since any name
12580Sstevel@tonic-gate  * may be valid.
12590Sstevel@tonic-gate  *
12600Sstevel@tonic-gate  * ret 0:	non-empty string
12610Sstevel@tonic-gate  * ret -1:	empty string or string is too long.
12620Sstevel@tonic-gate  */
12630Sstevel@tonic-gate static int
proc_zonename(char * optstr)12640Sstevel@tonic-gate proc_zonename(char *optstr)
12650Sstevel@tonic-gate {
12660Sstevel@tonic-gate 	size_t	length = strlen(optstr);
12670Sstevel@tonic-gate 	if ((length < 1) || (length > ZONENAME_MAX)) {
12680Sstevel@tonic-gate 		(void) sprintf(errbuf,
12690Sstevel@tonic-gate 		    gettext("invalid zone name: %s"), optstr);
12700Sstevel@tonic-gate 		error_str = errbuf;
12710Sstevel@tonic-gate 		return (-1);
12720Sstevel@tonic-gate 	}
12730Sstevel@tonic-gate 	zonename = strdup(optstr);
12740Sstevel@tonic-gate 	flags |= M_ZONENAME;
12750Sstevel@tonic-gate 	return (0);
12760Sstevel@tonic-gate }
12771780Sgww 
12781780Sgww /*
12791780Sgww  * proc_frmi - set up frmi for pattern matching.
12801780Sgww  *	Logic ripped off of scf_walk_fmri()
12811780Sgww  *		Thanks to the smf team.
12821780Sgww  *
12831780Sgww  * ret 0:	OK
12841780Sgww  * ret -1:	error
12851780Sgww  */
12861780Sgww static int
proc_fmri(char * optstr)12871780Sgww proc_fmri(char *optstr)
12881780Sgww {
12891780Sgww 	if (strpbrk(optstr, "*?[") != NULL) {
12901780Sgww 		/* have a pattern to glob for */
12911780Sgww 
12921780Sgww 		fmri.sp_type = PATTERN_GLOB;
12931780Sgww 		if (optstr[0] == '*' ||
12941780Sgww 		    (strlen(optstr) >= 4 && optstr[3] == ':')) {
12951780Sgww 			fmri.sp_arg = strdup(optstr);
12961780Sgww 		} else if ((fmri.sp_arg = malloc(strlen(optstr) + 6)) != NULL) {
12971780Sgww 			(void) snprintf(fmri.sp_arg, strlen(optstr) + 6,
12981780Sgww 			    "svc:/%s", optstr);
12991780Sgww 		}
13001780Sgww 	} else {
13011780Sgww 		fmri.sp_type = PATTERN_PARTIAL;
13021780Sgww 		fmri.sp_arg = strdup(optstr);
13031780Sgww 	}
13041780Sgww 	if (fmri.sp_arg == NULL)
13051780Sgww 		return (-1);
13061780Sgww 
13071780Sgww 	return (0);
13081780Sgww }
1309