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