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
check_inputs(int flags,const char * separator)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
print_audit_xml_prolog_buf(char * out_buf,const int out_buf_len)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
print_audit_xml_ending_buf(char * out_buf,const int out_buf_len)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
print_audit_xml_prolog(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
print_audit_xml_ending(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
checkpoint_progress(pr_context_t * context)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
print_audit_buf(char ** in_buf,int * in_buf_len,char ** out_buf,int * out_buf_len,const int flags,const char * separator)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
print_audit(const int flags,const char * separator)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
print_audit_common(pr_context_t * context,const int flags,const char * separator)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
token_processing(pr_context_t * context)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