xref: /illumos-gate/usr/src/cmd/praudit/printaudit.c (revision 86d949f9497332fe19be6b5d711d265eb957439f)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <dirent.h>
28 #include <locale.h>
29 #include <libintl.h>
30 #include <stdlib.h>
31 #include <strings.h>
32 #include <stdio.h>
33 #include <unistd.h>
34 
35 #include <sys/types.h>
36 #include <sys/file.h>
37 
38 #include <bsm/audit.h>
39 #include <bsm/audit_record.h>
40 #include <bsm/libbsm.h>
41 
42 #include "praudit.h"
43 #include "toktable.h"
44 
45 extern void	init_tokens(void);	/* shared with auditreduce */
46 
47 static int	check_inputs(int flags, const char *separator);
48 static void	checkpoint_progress(pr_context_t *context);
49 static int	print_audit_common(pr_context_t *context, int flags,
50     const char *separator);
51 static int	token_processing(pr_context_t *context);
52 
53 static int	initdone = 0;
54 
55 /*
56  * This source is shared outside of praudit; the following lint directive
57  * is needed to suppress praudit lint warnings about unused functions, for
58  * functions which are only invoked outside praudit.
59  */
60 
61 /*LINTLIBRARY*/
62 
63 /*
64  * ----------------------------------------------------------------------
65  * check_inputs() - check input flags and delimiter.
66  *		Returns:
67  *		    0 - successful
68  *		   -1 - invalid inputs. errno is set to EINVAL
69  * ----------------------------------------------------------------------
70  */
71 static int
72 check_inputs(int flags, const char *separator)
73 {
74 	if ((flags & PRF_RAWM) && (flags & PRF_SHORTM)) {
75 		errno = EINVAL;
76 		return (-1);
77 	}
78 
79 	/* Ignore the delimiter when XML is specified */
80 	if (!(flags & PRF_XMLM) && (strlen(separator) >= SEP_SIZE)) {
81 		errno = EINVAL;
82 		return (-1);
83 	}
84 
85 	return (0);
86 }
87 
88 /*
89  * ----------------------------------------------------------------------
90  * print_audit_xml_prolog_buf() - print the XML prolog.
91  *		    0 - successful
92  *		   -1 - output buffer too small. errno is set to ENOSPC
93  * ----------------------------------------------------------------------
94  */
95 int
96 print_audit_xml_prolog_buf(char *out_buf, const int out_buf_len)
97 {
98 	if (xml_prolog_len > out_buf_len) {
99 		errno = ENOSPC;
100 		return (-1);
101 	}
102 
103 	(void) snprintf(out_buf, out_buf_len, "%s%s%s%s", prolog1, prolog_xsl,
104 	    prolog2, xml_start);
105 
106 	return (0);
107 }
108 
109 /*
110  * ----------------------------------------------------------------------
111  * print_audit_xml_ending_buf() - print the XML ending.
112  *		    0 - successful
113  *		   -1 - output buffer too small. errno is set to ENOSPC
114  * ----------------------------------------------------------------------
115  */
116 int
117 print_audit_xml_ending_buf(char *out_buf, const int out_buf_len)
118 {
119 	if (xml_end_len > out_buf_len) {
120 		errno = ENOSPC;
121 		return (-1);
122 	}
123 
124 	(void) snprintf(out_buf, out_buf_len, "%s", xml_ending);
125 	return (0);
126 }
127 
128 /*
129  * ----------------------------------------------------------------------
130  * print_prolog() - print the XML prolog.
131  * ----------------------------------------------------------------------
132  */
133 void
134 print_audit_xml_prolog(void)
135 {
136 	(void) printf("%s%s%s%s", prolog1, prolog_xsl, prolog2, xml_start);
137 }
138 
139 /*
140  * ----------------------------------------------------------------------
141  * print_ending() - print the XML ending.
142  * ----------------------------------------------------------------------
143  */
144 void
145 print_audit_xml_ending(void)
146 {
147 	(void) printf("%s", xml_ending);
148 }
149 
150 /*
151  * ----------------------------------------------------------------------
152  * checkpoint_progress() - If starting a new file or header token,
153  *      checkpoint as needed to mark progress.
154  * ----------------------------------------------------------------------
155  */
156 static void
157 checkpoint_progress(pr_context_t *context)
158 {
159 	int	tokenid = context->tokenid;
160 
161 	if (is_file_token(tokenid) || is_header_token(tokenid)) {
162 		if (context->data_mode == BUFMODE) {
163 			context->inbuf_last = context->audit_adr->adr_now - 1;
164 			context->outbuf_last = context->outbuf_p;
165 		}
166 		context->audit_rec_start = context->audit_adr->adr_now - 1;
167 		if (is_file_token(tokenid)) {
168 			context->audit_rec_len = 11;
169 		}
170 	}
171 }
172 
173 /*
174  * ----------------------------------------------------------------------
175  * print_audit_buf() - display contents of audit trail file
176  *
177  *		   Parses the binary audit data from the specified input
178  *		   buffer, and formats as requested to the specified output
179  *		   buffer.
180  *
181  *	inputs:
182  *		   in_buf, -	address and length of binary audit input.
183  *		   in_buf_len
184  *		   out_buf, -	address and length of output buffer to
185  *		   out_buf_len	copy formatted audit data to.
186  *		   flags -	formatting flags as defined in praudit.h
187  *		   separator -	field delimiter (or NULL if the default
188  *				delimiter of comma is to be used).
189  *
190  * return codes:    0 - success
191  *		ENOSPC...
192  * ----------------------------------------------------------------------
193  */
194 int
195 print_audit_buf(char **in_buf, int *in_buf_len, char **out_buf,
196     int *out_buf_len, const int flags, const char *separator)
197 {
198 	int	retstat = 0;
199 	pr_context_t	*context;
200 
201 	if ((retstat = check_inputs(flags, separator)) != 0)
202 		return (retstat);
203 
204 	if ((context = (pr_context_t *)malloc(sizeof (pr_context_t))) == NULL) {
205 		errno = EPERM;
206 		return (-1);
207 	}
208 
209 	/* Init internal pointers and lengths... */
210 	context->data_mode = BUFMODE;
211 	context->inbuf_last = context->inbuf_start = *in_buf;
212 	context->inbuf_totalsize = *in_buf_len;
213 
214 	context->pending_flag = 0;
215 	context->current_rec = 0;
216 
217 	context->outbuf_last = context->outbuf_start =
218 	    context->outbuf_p = *out_buf;
219 	context->outbuf_remain_len = *out_buf_len;
220 
221 	/*
222 	 * get an adr pointer to the audit input buf
223 	 */
224 	context->audit_adr = (adr_t *)malloc(sizeof (adr_t));
225 	(void) adrm_start(context->audit_adr, *in_buf);
226 	context->audit_rec_start = NULL;
227 	context->audit_rec_len = 0;
228 
229 	retstat = print_audit_common(context, flags, separator);
230 
231 	/* Check for and handle partial results as needed */
232 	if (retstat != 0) {
233 		*in_buf = context->inbuf_last;
234 		*in_buf_len = context->inbuf_totalsize -
235 		    (context->inbuf_last - context->inbuf_start);
236 
237 		/* Return size of output */
238 		*out_buf_len = context->outbuf_last - context->outbuf_start;
239 		if (*out_buf_len > 0) {
240 			/* null-terminate the output */
241 			*(context->outbuf_last) = '\0';
242 			*out_buf_len = *out_buf_len + 1;
243 		}
244 	} else {
245 		/* Return size of output */
246 		*out_buf_len = context->outbuf_p - context->outbuf_start + 1;
247 		*(context->outbuf_p) = '\0';	/* null-terminate the output */
248 	}
249 
250 	(void) free(context->audit_adr);
251 	(void) free(context);
252 	return (retstat);
253 }
254 
255 /*
256  * ----------------------------------------------------------------------
257  * print_audit() - display contents of audit trail file
258  *
259  *		   Parses the binary audit data from the file mapped as stdin,
260  *		   and formats as requested to file mapped as stdout.
261  *	inputs:
262  *		   flags -	formatting flags as defined in praudit.h
263  *		   separator -	field delimiter (or NULL if the default
264  *				delimiter of comma is to be used).
265  *
266  * return codes:   -1 - error
267  *		    0 - successful
268  * ----------------------------------------------------------------------
269  */
270 int
271 print_audit(const int flags, const char *separator)
272 {
273 	int	retstat = 0;
274 	pr_context_t	*context;
275 
276 	if ((retstat = check_inputs(flags, separator)) != 0)
277 		return (retstat);
278 
279 	if ((context = (pr_context_t *)malloc(sizeof (pr_context_t))) == NULL) {
280 		errno = EPERM;
281 		return (-1);
282 	}
283 
284 	/*
285 	 * get an adr pointer to the current audit file (stdin)
286 	 */
287 	context->audit_adr = malloc(sizeof (adr_t));
288 	context->audit_adrf = malloc(sizeof (adrf_t));
289 
290 	adrf_start(context->audit_adrf, context->audit_adr, stdin);
291 
292 	context->data_mode = FILEMODE;
293 	context->audit_rec_start = NULL;
294 	context->audit_rec_len = 0;
295 
296 	context->pending_flag = 0;
297 	context->current_rec = 0;
298 
299 	retstat = print_audit_common(context, flags, separator);
300 
301 	(void) free(context->audit_adr);
302 	(void) free(context->audit_adrf);
303 	(void) free(context);
304 	return (retstat);
305 }
306 
307 /*
308  * ----------------------------------------------------------------------
309  * print_audit_common() - common routine for print_audit* functions.
310  *
311  *		   Parses the binary audit data, and formats as requested.
312  *		   The context parameter defines whether the source of the
313  *		   audit data is a buffer, or a file mapped to stdin, and
314  *		   whether the output is to a buffer or a file mapped to
315  *		   stdout.
316  *
317  *	inputs:
318  *		   context -	defines the context of the request, including
319  *				info about the source and output.
320  *		   flags -	formatting flags as defined in praudit.h
321  *		   separator -	field delimiter (or NULL if the default
322  *				delimiter of comma is to be used).
323  *
324  * return codes:   -1 - error
325  *		    0 - successful
326  * ----------------------------------------------------------------------
327  */
328 static int
329 print_audit_common(pr_context_t *context, const int flags,
330     const char *separator)
331 {
332 	int	retstat = 0;
333 
334 	if (!initdone) {
335 		init_tokens();
336 		initdone++;
337 	}
338 
339 	context->format = flags;
340 
341 	/* start with default delimiter of comma */
342 	(void) strlcpy(context->SEPARATOR, ",", SEP_SIZE);
343 	if (separator != NULL) {
344 		if (strlen(separator) < SEP_SIZE) {
345 			(void) strlcpy(context->SEPARATOR, separator, SEP_SIZE);
346 		}
347 	}
348 
349 	while ((retstat == 0) && pr_input_remaining(context, 1)) {
350 		if (pr_adr_char(context, (char *)&(context->tokenid), 1) == 0) {
351 			retstat = token_processing(context);
352 		} else
353 			break;
354 	}
355 
356 	/*
357 	 * For buffer processing, if the entire input buffer was processed
358 	 * successfully, but the last record in the buffer was incomplete
359 	 * (according to the length from its header), then reflect an
360 	 * "incomplete input" error (which will cause partial results to be
361 	 * returned).
362 	 */
363 	if ((context->data_mode == BUFMODE) && (retstat == 0) &&
364 	    (context->audit_adr->adr_now < (context->audit_rec_start +
365 	    context->audit_rec_len))) {
366 		retstat = -1;
367 		errno = EIO;
368 	}
369 
370 	/*
371 	 * If there was a last record that didn't get officially closed
372 	 * off, do it now.
373 	 */
374 	if ((retstat == 0) && (context->format & PRF_XMLM) &&
375 	    (context->current_rec)) {
376 		retstat = do_newline(context, 1);
377 		if (retstat == 0)
378 			retstat = close_tag(context, context->current_rec);
379 	}
380 
381 	return (retstat);
382 }
383 
384 /*
385  * -----------------------------------------------------------------------
386  * token_processing:
387  *		  Calls the routine corresponding to the token id
388  *		  passed in the parameter from the token table, tokentable
389  * return codes : -1 - error
390  *		:  0 - successful
391  * -----------------------------------------------------------------------
392  */
393 static int
394 token_processing(pr_context_t *context)
395 {
396 	uval_t	uval;
397 	int	retstat;
398 	int	tokenid = context->tokenid;
399 
400 	if ((tokenid > 0) && (tokenid <= MAXTOKEN) &&
401 	    (tokentable[tokenid].func != NOFUNC)) {
402 		/*
403 		 * First check if there's a previous record that needs to be
404 		 * closed off now; then checkpoint our progress as needed.
405 		 */
406 		if ((retstat = check_close_rec(context, tokenid)) != 0)
407 			return (retstat);
408 		checkpoint_progress(context);
409 
410 		/* print token name */
411 		if (context->format & PRF_XMLM) {
412 			retstat = open_tag(context, tokenid);
413 		} else {
414 			if (!(context->format & PRF_RAWM) &&
415 			    (tokentable[tokenid].t_name != (char *)0)) {
416 				uval.uvaltype = PRA_STRING;
417 				uval.string_val =
418 				    gettext(tokentable[tokenid].t_name);
419 			} else {
420 				uval.uvaltype = PRA_BYTE;
421 				uval.char_val = tokenid;
422 			}
423 			retstat = pa_print(context, &uval, 0);
424 		}
425 		if (retstat == 0)
426 			retstat = (*tokentable[tokenid].func)(context);
427 
428 		/*
429 		 * For XML, close the token tag. Header tokens wrap the
430 		 * entire record, so they only get closed later implicitly;
431 		 * here, just make sure the header open tag gets finished.
432 		 */
433 		if ((retstat == 0) && (context->format & PRF_XMLM)) {
434 			if (!is_header_token(tokenid))
435 				retstat = close_tag(context, tokenid);
436 			else
437 				retstat = finish_open_tag(context);
438 		}
439 		return (retstat);
440 	}
441 	/* here if token id is not in table */
442 	(void) fprintf(stderr, gettext("praudit: No code associated with "
443 	    "token id %d\n"), tokenid);
444 	return (0);
445 }
446