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