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