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