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 (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
23  */
24 
25 /*
26  * get audit preselection mask values
27  */
28 
29 #include <ctype.h>
30 #include <stdio.h>
31 #include <string.h>
32 
33 #include <sys/errno.h>
34 #include <sys/types.h>
35 #include <bsm/audit.h>
36 #include <bsm/libbsm.h>
37 
38 #include <adt_xlate.h>		/* adt_write_syslog */
39 
40 #define	SUCCESS 0x1		/* '+' success mask */
41 #define	FAILURE	0x2		/* '-' failure mask */
42 #define	INVERSE	0x4		/* '^' invert the mask */
43 
44 static int
45 match_class(char *s, char *prefix, uint_t m, int v)
46 {
47 	au_class_ent_t *p_class;
48 
49 	(void) strcat(s, prefix);
50 	if (cacheauclass(&p_class, m) == 1) {
51 		if (v == 0) {
52 			(void) strncat(s, p_class->ac_name, AU_CLASS_NAME_MAX);
53 		} else {
54 			(void) strncat(s, p_class->ac_desc, AU_CLASS_DESC_MAX);
55 		}
56 		(void) strcat(s, ",");
57 		return (0);
58 	}
59 	return (-1);
60 }
61 
62 /*
63  * getauditflagschar() - convert bit flag to character string
64  *
65  * input:	masks->am_success - audit on success
66  *		masks->am_failure - audit on failure
67  *		verbose - string format. 0 if short name; 1 if long name;
68  *
69  * output: auditstring - resultant audit string
70  *
71  * returns: 	0 - entry read ok
72  *		-1 - error
73  */
74 
75 int
76 getauditflagschar(char *auditstring, au_mask_t *masks, int verbose)
77 {
78 	char	*prefix;		/* +, -, or null */
79 	unsigned int	m;		/* for masking with masks */
80 	au_mask_t all; 		/* value for the string "all" */
81 	int	plus_all = 0;	/* true if +all */
82 	int	minus_all = 0;	/* true if -all */
83 	int	l;
84 
85 	/* initialize input buffer */
86 	*auditstring = '\0';
87 	/* no masks, no flags; we're outta here */
88 	if ((masks->am_success == 0) && (masks->am_failure == 0)) {
89 		if (match_class(auditstring, "", 0, verbose) != 0)
90 			return (-1);
91 		/* kludge to get rid of trailing comma */
92 		l = strlen(auditstring) - 1;
93 		if (auditstring[l] == ',')
94 			auditstring[l] = '\0';
95 		return (0);
96 	}
97 	/* Get the mask value for the string "all" */
98 	all.am_success = 0;
99 	all.am_failure = 0;
100 	if (getauditflagsbin("all", &all) != 0)
101 		return (-1);
102 	if (all.am_success == masks->am_success) {
103 		if (all.am_failure == masks->am_failure) {
104 			(void) strcat(auditstring, "all");
105 			return (0);
106 		}
107 		(void) strcat(auditstring, "+all,");
108 		plus_all = 1;
109 	} else if (all.am_failure == masks->am_failure) {
110 		(void) strcat(auditstring, "-all,");
111 		minus_all = 1;
112 	}
113 	for (m = (unsigned)0x80000000; m != 0; m >>= 1) {
114 		if (m & masks->am_success & masks->am_failure)
115 			prefix = plus_all ? "-" : (minus_all ? "+" : "");
116 		else if (m & masks->am_success)
117 			prefix = "+";
118 		else if (m & masks->am_failure)
119 			prefix = "-";
120 		else
121 			continue;
122 		if (match_class(auditstring, prefix, m, verbose) != 0)
123 			return (-1);
124 	}
125 	if (*(prefix = auditstring + strlen(auditstring) - 1) == ',')
126 		*prefix = '\0';
127 	return (0);
128 
129 }
130 
131 /*
132  *  Audit flags:
133  *
134  *	[+ | - | ^ | ^+ | ^-]<classname>{,[+ | - | ^ | ^+ | ^-]<classname>}*
135  *
136  *	  <classname>, add class mask to success and failure mask.
137  *	 +<classname>, add class mask only to success mask.
138  *	 -<classname>, add class mask only to failure mask.
139  *	 ^<classname>, remove class mask from success and failure mask.
140  *	^+<classname>, remove class mask from success mask.
141  *	^-<classname>, remove class mask from failure mask.
142  */
143 
144 /*
145  * __chkflags - check if the audit flags are valid for this system
146  *
147  *	Entry	flags = audit flags string.
148  *		cont  = B_TRUE, continue parsing even if error.
149  *			B_FALSE, return failure on error.
150  *
151  *	Exit	mask = audit mask as defined by flags.
152  *
153  *	Return	B_TRUE if no errors, or continue == B_TRUE.
154  *		B_FALSE and if error != NULL, flags in error.
155  */
156 
157 boolean_t
158 __chkflags(char *flags, au_mask_t *mask, boolean_t cont, char **error)
159 {
160 	uint32_t	prefix;
161 	au_class_ent_t	*class;
162 	char		name[AU_CLASS_NAME_MAX+1];
163 	int		i;
164 
165 	if (flags == NULL || mask == NULL) {
166 		return (B_FALSE);
167 	}
168 
169 	mask->am_success = 0;
170 	mask->am_failure = 0;
171 
172 	while (*flags != '\0') {
173 		prefix = (SUCCESS | FAILURE);
174 
175 		/* skip white space */
176 		while (isspace(*flags)) {
177 			flags++;
178 		}
179 
180 		if (*flags == '\0') {
181 			break;
182 		}
183 		if (error != NULL) {
184 			/* save error pointer */
185 			*error = flags;
186 		}
187 
188 		/* get the prefix */
189 		if (*flags == '+') {
190 			flags++;
191 			prefix ^= FAILURE;
192 		} else if (*flags == '-') {
193 			flags++;
194 			prefix ^= SUCCESS;
195 		} else if (*flags == '^') {
196 			flags++;
197 			prefix |= INVERSE;
198 			if (*flags == '+') {
199 				flags++;
200 				prefix ^= FAILURE;
201 			} else if (*flags == '-') {
202 				flags++;
203 				prefix ^= SUCCESS;
204 			}
205 		}
206 
207 		/* get class name */
208 
209 		for (i = 0; (i < sizeof (name) - 1) &&
210 		    !(*flags == '\0' || *flags == ','); i++) {
211 			name[i] = *flags++;
212 		}
213 		name[i++] = '\0';
214 		if (*flags == ',') {
215 			/* skip comma (',') */
216 			flags++;
217 		}
218 		if (cacheauclassnam(&class, name) != 1) {
219 			if (!cont) {
220 				return (B_FALSE);
221 			} else {
222 				char	msg[512];
223 
224 				(void) snprintf(msg, sizeof (msg), "invalid "
225 				    "audit flag %s", name);
226 				adt_write_syslog(msg, EINVAL);
227 			}
228 		} else {
229 			/* add class mask */
230 
231 			if ((prefix & (INVERSE | SUCCESS)) == SUCCESS) {
232 				mask->am_success |= class->ac_class;
233 			} else if ((prefix & (INVERSE | SUCCESS)) ==
234 			    (INVERSE | SUCCESS)) {
235 				mask->am_success &= ~(class->ac_class);
236 			}
237 			if ((prefix & (INVERSE | FAILURE)) == FAILURE) {
238 				mask->am_failure |= class->ac_class;
239 			} else if ((prefix & (INVERSE | FAILURE)) ==
240 			    (INVERSE | FAILURE)) {
241 				mask->am_failure &= ~(class->ac_class);
242 			}
243 		}
244 	}
245 
246 	return (B_TRUE);
247 }
248 
249 /*
250  * getauditflagsbin() -  converts character string to success and
251  *			 failure bit masks
252  *
253  * input:	auditstring - audit string
254  *
255  * output:	masks->am_success - audit on success
256  *		masks->am_failure - audit on failure
257  *
258  * returns: 0 - ok
259  *          -1 - error - string or mask NULL.
260  */
261 
262 int
263 getauditflagsbin(char *auditstring, au_mask_t *masks)
264 {
265 	if (__chkflags(auditstring, masks, B_TRUE, NULL)) {
266 		return (0);
267 	}
268 	return (-1);
269 }
270