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 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 * 26 * convert binary audit records to syslog messages and 27 * send them off to syslog 28 * 29 */ 30 #pragma ident "%Z%%M% %I% %E% SMI" 31 32 /* 33 * auditd_plugin_open(), auditd_plugin() and auditd_plugin_close() 34 * implement a replacable library for use by auditd; they are a 35 * project private interface and may change without notice. 36 * 37 */ 38 #define DEBUG 0 39 #if DEBUG 40 #define DPRINT(x) {fprintf x; } 41 #else 42 #define DPRINT(x) 43 #endif 44 45 #include <arpa/inet.h> 46 #include <assert.h> 47 #include <errno.h> 48 #include <fcntl.h> 49 #include <grp.h> 50 #include <libintl.h> 51 #include <netdb.h> 52 #include <netinet/in.h> 53 #include <pthread.h> 54 #include <pwd.h> 55 #include <stdio.h> 56 #include <stdlib.h> 57 #include <string.h> 58 #include <time.h> 59 #include <syslog.h> 60 #include <sys/types.h> 61 #include <sys/socket.h> 62 #include <unistd.h> 63 64 #include <bsm/audit.h> 65 #include <bsm/audit_record.h> 66 #include <security/auditd.h> 67 68 #include "toktable.h" 69 #include "sysplugin.h" 70 #include "systoken.h" 71 #include <audit_plugin.h> 72 73 #if DEBUG 74 static FILE *dbfp; /* debug file */ 75 #endif 76 77 extern void init_tokens(); 78 extern int parse_token(parse_context_t *); 79 80 static au_mask_t mask; 81 static int initialized = 0; 82 static size_t maxavail; 83 static pthread_mutex_t log_mutex; 84 85 #define ELLIPSIS "..." 86 #define ELLIPSIS_SIZE (sizeof (ELLIPSIS) - 1) 87 88 /* 89 * simple hashing for uid and hostname lookup 90 * 91 * performance tests showed that cacheing the hostname, uid, and gid 92 * make about a 40% difference for short audit records and regularly 93 * repeating hostname, uid, etc 94 * 95 * ht_type and ht_ip are only used for hostname lookup cacheing. 96 */ 97 typedef struct hashtable { 98 uint32_t ht_key; 99 uint32_t ht_type; 100 uint32_t ht_ip[4]; 101 char *ht_value; 102 size_t ht_length; 103 } hashtable_t; 104 #define HOSTHASHSIZE 128 105 #define UIDHASHSIZE 128 106 #define GIDHASHSIZE 32 107 108 static hashtable_t uidhash[UIDHASHSIZE]; 109 static hashtable_t gidhash[GIDHASHSIZE]; 110 static hashtable_t hosthash[HOSTHASHSIZE]; 111 112 #define STRCONSTARGS(s) (s), (sizeof (s) - 1) 113 /* 114 * the hash "handles" collisions by overwriting the old 115 * hash entry with the new. Perfection is not the goal. 116 * 117 * the key (s) is a 32 bit integer, handled here as 118 * four bytes. If the hash size is increased beyond 119 * 256, this macro will need some work. 120 */ 121 #define HASH(s, r, m) {\ 122 uint32_t _mush = 0;\ 123 int _i;\ 124 for (_i = 0; _i < 4; _i++) {\ 125 _mush ^= *(s)++;\ 126 }\ 127 r = _mush % m;\ 128 } 129 130 131 /* 132 * The default mask for sysplugin is to reject all record types. 133 * The parameters input here select which classes to allow. 134 * 135 * getauditflgsbin() outputs error messages to syslog. 136 * 137 * caller must hold log_mutex 138 */ 139 140 static auditd_rc_t 141 setmask(const char *flags) 142 { 143 au_mask_t tmask; 144 char *input, *ip, c; 145 auditd_rc_t rc = AUDITD_SUCCESS; 146 147 mask.am_success = 0x0; 148 mask.am_failure = 0x0; 149 150 if (flags != NULL) { 151 /* 152 * getauditflagsbin doesn't like blanks, but admins do 153 */ 154 input = malloc(strlen(flags) + 1); 155 if (input == NULL) 156 return (AUDITD_NO_MEMORY); 157 158 ip = input; 159 160 for (; (c = *flags) != '\0'; flags++) { 161 if (c == ' ') 162 continue; 163 *ip++ = c; 164 } 165 *ip = '\0'; 166 if (getauditflagsbin(input, &tmask) == 0) { 167 mask.am_success |= tmask.am_success; 168 mask.am_failure |= tmask.am_failure; 169 } 170 } 171 if ((mask.am_success | mask.am_failure) == 0) { 172 rc = AUDITD_INVALID; 173 __audit_syslog("audit_syslog.so", LOG_CONS | LOG_NDELAY, 174 LOG_DAEMON, LOG_ERR, 175 gettext("plugin is configured with empty class mask\n")); 176 } 177 free(input); 178 return (rc); 179 } 180 181 /* 182 * based on the current value of mask, either keep or toss the 183 * current audit record. The input is 1 for success, -1 for 184 * failure. 0 means no exit or return token was seen. 185 * 186 * au_preselect returns 1 for keep it, 0 for delete it, and 187 * -1 for some sort of error. Here, 1 and -1 are considered 188 * equivalent. tossit() returns 1 for delete it and 0 for 189 * keep it. 190 */ 191 192 static int 193 tossit(au_event_t id, int passfail) 194 { 195 int rc; 196 int selFlag; 197 198 switch (passfail) { 199 case 1: 200 selFlag = AU_PRS_SUCCESS; 201 break; 202 case -1: 203 selFlag = AU_PRS_FAILURE; 204 break; 205 default: /* no exit or return token */ 206 selFlag = AU_PRS_BOTH; 207 break; 208 } 209 (void) pthread_mutex_lock(&log_mutex); 210 rc = au_preselect(id, &mask, selFlag, AU_PRS_USECACHE); 211 (void) pthread_mutex_unlock(&log_mutex); 212 213 return (rc == 0); 214 } 215 216 /* 217 * the three bytes for ellipsis could potentially be longer than the 218 * space available for text if maxavail is within two bytes of 219 * OUTPUT_BUF_SIZE, which can happen if the hostname is one or two 220 * characters long. If there isn't room for ellipsis, there isn't 221 * room for the data, so it is simply dropped. 222 */ 223 224 static size_t 225 fromleft(char *p, size_t avail, char *attrname, size_t attrlen, char *txt, 226 size_t txtlen) 227 { 228 size_t len; 229 230 if (avail < attrlen + ELLIPSIS_SIZE) 231 return (0); 232 233 (void) memcpy(p, attrname, attrlen); 234 p += attrlen; 235 avail -= attrlen; 236 if (txtlen > avail) { 237 (void) memcpy(p, ELLIPSIS, ELLIPSIS_SIZE); 238 txt += txtlen - (avail - ELLIPSIS_SIZE); 239 (void) memcpy(p + ELLIPSIS_SIZE, txt, avail - ELLIPSIS_SIZE); 240 len = attrlen + avail; 241 p += avail; 242 } else { 243 (void) memcpy(p, txt, txtlen); 244 len = attrlen + txtlen; 245 p += txtlen; 246 } 247 *p = '\0'; 248 return (len); 249 } 250 251 static size_t 252 fromright(char *p, size_t avail, char *attrname, size_t attrlen, char *txt, 253 size_t txtlen) 254 { 255 size_t len; 256 257 if (avail < attrlen + ELLIPSIS_SIZE) 258 return (0); 259 260 (void) memcpy(p, attrname, attrlen); 261 p += attrlen; 262 avail -= attrlen; 263 if (txtlen > avail) { 264 (void) memcpy(p, txt, avail - ELLIPSIS_SIZE); 265 (void) memcpy(p + (avail - ELLIPSIS_SIZE), 266 ELLIPSIS, ELLIPSIS_SIZE); 267 len = attrlen + avail; 268 p += avail; 269 } else { 270 (void) memcpy(p, txt, txtlen); 271 p += txtlen; 272 len = attrlen + txtlen; 273 } 274 *p = '\0'; 275 return (len); 276 } 277 278 static int 279 init_hash(hashtable_t *table, int bad_key, int table_length, 280 size_t max_value) 281 { 282 int i; 283 284 for (i = 0; i < table_length; i++) { 285 table[i].ht_value = malloc(max_value + 1); 286 table[i].ht_key = bad_key; 287 table[i].ht_length = 0; 288 if (table[i].ht_value == NULL) { 289 int j; 290 for (j = 0; j < i; j++) 291 free(table[j].ht_value); 292 return (-1); 293 } 294 *(table[i].ht_value) = '\0'; 295 } 296 return (0); 297 } 298 299 static void 300 free_hash(hashtable_t *table, int table_length) 301 { 302 int i; 303 304 for (i = 0; i < table_length; i++) { 305 free(table[i].ht_value); 306 } 307 } 308 309 310 /* 311 * do IP -> hostname lookup 312 */ 313 #define UNKNOWN "unknown" 314 #define UNKNOWN_LEN (sizeof (UNKNOWN)) 315 316 static size_t 317 gethname(au_tid_addr_t *tid, char *p, size_t max, char *prefix, 318 size_t prefix_len) 319 { 320 size_t len, l; 321 struct hostent *host; 322 int rc; 323 int af; 324 int ix; 325 char *hash_key; 326 uint32_t key; 327 int match; 328 329 if (prefix_len > max) 330 return (0); 331 332 (void) memcpy(p, prefix, prefix_len); 333 p += prefix_len; 334 max -= prefix_len; 335 336 if (tid->at_type == AU_IPv6) { 337 key = tid->at_addr[0] ^ 338 tid->at_addr[1] ^ 339 tid->at_addr[2] ^ 340 tid->at_addr[3]; 341 } else 342 key = (tid->at_addr[0]); 343 344 hash_key = (char *)&key; 345 346 HASH(hash_key, ix, HOSTHASHSIZE); 347 348 match = 0; 349 350 if (key == 0) { 351 l = UNKNOWN_LEN; /* includes end of string */ 352 if (l > max) 353 l = max; 354 len = prefix_len + strlcpy(p, UNKNOWN, l); 355 return (len); 356 } 357 358 if (tid->at_type == AU_IPv6) { 359 if ((key == hosthash[ix].ht_key) && 360 (hosthash[ix].ht_type == tid->at_type)) { 361 int i; 362 match = 1; 363 for (i = 0; i < 4; i++) { 364 if (hosthash[ix].ht_ip[i] != tid->at_addr[i]) { 365 match = 0; 366 break; 367 } 368 } 369 } 370 } else if (key == hosthash[ix].ht_key) { 371 match = 1; 372 } 373 if (!match) { 374 hosthash[ix].ht_key = key; 375 hosthash[ix].ht_type = tid->at_type; 376 377 if (tid->at_type == AU_IPv4) { 378 hosthash[ix].ht_ip[0] = tid->at_addr[0]; 379 af = AF_INET; 380 } else { 381 (void) memcpy((char *)hosthash[ix].ht_ip, 382 (char *)tid->at_addr, AU_IPv6); 383 af = AF_INET6; 384 } 385 host = getipnodebyaddr((const void *)tid->at_addr, 386 tid->at_type, af, &rc); 387 388 if (host == NULL) { 389 (void) inet_ntop(af, (void *)tid->at_addr, 390 hosthash[ix].ht_value, MAXHOSTNAMELEN); 391 hosthash[ix].ht_length = strlen(hosthash[ix].ht_value); 392 } else { 393 hosthash[ix].ht_length = strlcpy(hosthash[ix].ht_value, 394 host->h_name, MAXHOSTNAMELEN); 395 freehostent(host); 396 } 397 } 398 l = hosthash[ix].ht_length + 1; 399 if (l > max) 400 l = max; 401 402 len = prefix_len + strlcpy(p, hosthash[ix].ht_value, l); 403 404 return (len); 405 } 406 /* 407 * the appropriate buffer length for getpwuid_r() isn't documented; 408 * 1024 should be enough. 409 */ 410 #define GETPWUID_BUFF_LEN 1024 411 #define USERNAMELEN 256 412 #define GIDNAMELEN 256 413 414 static size_t 415 getuname(uid_t uid, gid_t gid, char *p, size_t max, char *prefix, 416 size_t prefix_len) 417 { 418 struct passwd pw; 419 char pw_buf[GETPWUID_BUFF_LEN]; 420 size_t len, l; 421 struct group gr; 422 int ix; 423 char *hash_key; 424 425 if (prefix_len > max) 426 return (0); 427 428 len = prefix_len; 429 430 (void) memcpy(p, prefix, len); 431 p += len; 432 max -= len; 433 434 hash_key = (char *)&uid; 435 436 HASH(hash_key, ix, UIDHASHSIZE); 437 438 if (uid != uidhash[ix].ht_key) { 439 uidhash[ix].ht_key = uid; 440 441 if ((getpwuid_r(uid, &pw, pw_buf, GETPWUID_BUFF_LEN)) == NULL) 442 l = snprintf(uidhash[ix].ht_value, USERNAMELEN, 443 "%d", uid); 444 else 445 l = strlcpy(uidhash[ix].ht_value, pw.pw_name, 446 USERNAMELEN); 447 448 uidhash[ix].ht_length = l; 449 } 450 l = uidhash[ix].ht_length + 1; 451 if (l > max) 452 l = max; 453 (void) memcpy(p, uidhash[ix].ht_value, l); 454 len += l - 1; 455 456 if (gid != -2) { 457 p += l - 1; 458 max -= l - 1; 459 if (max < 2) 460 return (len); 461 462 hash_key = (char *)&gid; 463 HASH(hash_key, ix, GIDHASHSIZE); 464 465 if (gid != gidhash[ix].ht_key) { 466 gidhash[ix].ht_key = gid; 467 468 if (getgrgid_r(gid, &gr, pw_buf, GETPWUID_BUFF_LEN) == 469 NULL) 470 gidhash[ix].ht_length = 471 snprintf(gidhash[ix].ht_value, GIDNAMELEN, 472 "%d", gid); 473 else 474 gidhash[ix].ht_length = 475 strlcpy(gidhash[ix].ht_value, 476 gr.gr_name, GIDNAMELEN); 477 } 478 *p++ = ':'; 479 len++; 480 max--; 481 482 l = gidhash[ix].ht_length + 1; 483 if (l > max) 484 l = max; 485 (void) memcpy(p, gidhash[ix].ht_value, l); 486 len += l - 1; 487 } 488 return (len); 489 } 490 491 /* 492 * filter() parse input; toss if not wanted. 493 * 494 * the input value sequence is a number generated when the buffer 495 * was queued. ctx.out.sf_sequence, if not -1, is the sequence number 496 * generated in c2audit. It is not part of the "official" syslog 497 * output but is included if DEBUG is on. 498 */ 499 #define EVENT_NAME_LEN 32 500 501 static auditd_rc_t 502 filter(const char *input, uint32_t sequence, char *output, 503 size_t in_len, size_t out_len) 504 { 505 parse_context_t ctx; 506 char *bp; 507 auditd_rc_t rc = AUDITD_SUCCESS; 508 auditd_rc_t rc_ret = AUDITD_SUCCESS; 509 size_t used, remaining; 510 char *last_adr; /* infinite loop check */ 511 int token_count = 0; 512 int parse_rc; 513 514 static parse_context_t initial_ctx; 515 static int first = 1; 516 517 if (first) { 518 first = 0; 519 520 initial_ctx.out.sf_eventid = 0; 521 initial_ctx.out.sf_reclen = 0; 522 initial_ctx.out.sf_pass = 0; 523 initial_ctx.out.sf_asid = 0; 524 initial_ctx.out.sf_auid = -2; 525 initial_ctx.out.sf_euid = -2; 526 initial_ctx.out.sf_egid = -2; 527 initial_ctx.out.sf_tid.at_type = 0; 528 initial_ctx.out.sf_pauid = -2; 529 initial_ctx.out.sf_peuid = -2; 530 initial_ctx.out.sf_uauthlen = 0; 531 initial_ctx.out.sf_uauth = NULL; 532 initial_ctx.out.sf_pathlen = 0; 533 initial_ctx.out.sf_path = NULL; 534 initial_ctx.out.sf_atpathlen = 0; 535 initial_ctx.out.sf_atpath = NULL; 536 initial_ctx.out.sf_textlen = 0; 537 initial_ctx.out.sf_text = NULL; 538 initial_ctx.out.sf_sequence = -1; 539 initial_ctx.out.sf_zonelen = 0; 540 initial_ctx.out.sf_zonename = NULL; 541 542 init_tokens(); /* cmd/praudit/toktable.c */ 543 } 544 (void) memcpy(&ctx, &initial_ctx, sizeof (parse_context_t)); 545 ctx.id = sequence; 546 ctx.adr.adr_stream = (char *)input; 547 ctx.adr.adr_now = (char *)input; 548 549 last_adr = NULL; 550 while ((ctx.adr.adr_now - ctx.adr.adr_stream) < in_len) { 551 assert(last_adr != ctx.adr.adr_now); 552 token_count++; 553 last_adr = ctx.adr.adr_now; 554 if ((parse_rc = parse_token(&ctx)) != 0) { 555 char message[256]; 556 au_event_ent_t *event; 557 char event_name[EVENT_NAME_LEN]; 558 char sequence_str[EVENT_NAME_LEN]; 559 560 if (cacheauevent(&event, ctx.out.sf_eventid) < 0) 561 (void) snprintf(event_name, EVENT_NAME_LEN, 562 "%d", ctx.out.sf_eventid); 563 else 564 (void) strlcpy(event_name, event->ae_desc, 565 EVENT_NAME_LEN); 566 567 if (token_count < 2) 568 /* leave rc_ret unchanged */ 569 rc = AUDITD_INVALID; 570 571 if (ctx.out.sf_sequence != -1) 572 (void) snprintf(sequence_str, EVENT_NAME_LEN, 573 " (seq=%u) ", ctx.out.sf_sequence); 574 else 575 sequence_str[0] = '\0'; 576 577 (void) snprintf(message, 256, 578 gettext("error before token %d (previous token=%d)" 579 " of record type %s%s\n"), 580 token_count, parse_rc, event_name, sequence_str); 581 582 DPRINT((dbfp, message)); 583 584 __audit_syslog("audit_syslog.so", 585 LOG_PID | LOG_ODELAY | LOG_CONS, 586 LOG_DAEMON, LOG_ALERT, message); 587 break; 588 } 589 } 590 if (rc == AUDITD_SUCCESS) { 591 if (tossit(ctx.out.sf_eventid, ctx.out.sf_pass)) { 592 #if DEBUG 593 if (ctx.out.sf_sequence != -1) 594 fprintf(dbfp, 595 "syslog tossed (event=%d) record %u " 596 "/ buffer %u\n", 597 ctx.out.sf_eventid, ctx.out.sf_sequence, 598 sequence); 599 else 600 fprintf(dbfp, 601 "syslog tossed (event=%d) buffer %u\n", 602 ctx.out.sf_eventid, sequence); 603 #endif 604 return (-1); /* tell caller it was tossed */ 605 } 606 bp = output; 607 remaining = out_len; 608 609 if (ctx.out.sf_eventid != 0) { 610 au_event_ent_t *event; 611 612 if (cacheauevent(&event, ctx.out.sf_eventid) < 0) 613 used = snprintf(bp, remaining, "%d", 614 ctx.out.sf_eventid); 615 else 616 used = strlcpy(bp, event->ae_desc, remaining); 617 bp += used; 618 remaining -= used; 619 } 620 if (ctx.out.sf_pass != 0) { 621 if (ctx.out.sf_pass < 0) 622 used = strlcpy(bp, " failed", remaining); 623 else 624 used = strlcpy(bp, " ok", remaining); 625 bp += used; 626 remaining -= used; 627 } 628 if (ctx.out.sf_asid != 0) { 629 used = snprintf(bp, remaining, " session %u", 630 ctx.out.sf_asid); 631 remaining -= used; 632 bp += used; 633 } 634 if (ctx.out.sf_auid != -2) { 635 used = getuname(ctx.out.sf_auid, -2, bp, remaining, 636 STRCONSTARGS(" by ")); 637 bp += used; 638 remaining -= used; 639 } 640 if (ctx.out.sf_euid != -2) { 641 /* 4 = strlen(" as ") */ 642 used = getuname(ctx.out.sf_euid, ctx.out.sf_egid, bp, 643 remaining, STRCONSTARGS(" as ")); 644 bp += used; 645 remaining -= used; 646 } 647 if (ctx.out.sf_zonename != NULL) { 648 used = fromright(bp, remaining, 649 STRCONSTARGS(" in "), 650 ctx.out.sf_zonename, ctx.out.sf_zonelen); 651 free(ctx.out.sf_zonename); 652 bp += used; 653 remaining -= used; 654 } 655 if (ctx.out.sf_tid.at_type != 0) { 656 /* 6 = strlen(" from ") */ 657 used = gethname(&(ctx.out.sf_tid), bp, remaining, 658 STRCONSTARGS(" from ")); 659 bp += used; 660 remaining -= used; 661 } 662 if (ctx.out.sf_pauid != -2) { 663 /* 11 = strlen(" proc_auid ") */ 664 used = getuname(ctx.out.sf_pauid, -2, bp, remaining, 665 STRCONSTARGS(" proc_auid ")); 666 bp += used; 667 remaining -= used; 668 } 669 if (ctx.out.sf_peuid != -2) { 670 used = getuname(ctx.out.sf_peuid, -2, bp, remaining, 671 STRCONSTARGS(" proc_uid ")); 672 bp += used; 673 remaining -= used; 674 } 675 #if DEBUG 676 /* 677 * with performance testing, this has the effect of 678 * making that each message is unique, so syslogd 679 * won't collect a series of messages as "last message 680 * repeated n times," another reason why DEBUG 0 681 * should perform better than DEBUG 1. However the 682 * intention is to help debug lost data problems 683 */ 684 if (ctx.out.sf_sequence != -1) { 685 fprintf(dbfp, 686 "syslog writing record %u / buffer %u\n", 687 ctx.out.sf_sequence, sequence); 688 used = snprintf(bp, remaining, " seq %u", 689 ctx.out.sf_sequence, sequence); 690 remaining -= used; 691 bp += used; 692 } else 693 fprintf(dbfp, "syslog writing buffer %u\n", sequence); 694 #endif 695 /* 696 * Long fields that may need truncation go here in 697 * order of decreasing priority. Paths are truncated 698 * from the left, text from the right. 699 */ 700 if (ctx.out.sf_path != NULL) { 701 used = fromleft(bp, remaining, STRCONSTARGS(" obj "), 702 ctx.out.sf_path, ctx.out.sf_pathlen); 703 free(ctx.out.sf_path); 704 bp += used; 705 remaining -= used; 706 } 707 if (ctx.out.sf_atpath != NULL) { 708 used = fromleft(bp, remaining, 709 STRCONSTARGS(" attr_obj "), 710 ctx.out.sf_atpath, ctx.out.sf_atpathlen); 711 free(ctx.out.sf_atpath); 712 bp += used; 713 remaining -= used; 714 } 715 if (ctx.out.sf_uauth != NULL) { 716 used = fromright(bp, remaining, STRCONSTARGS(" uauth "), 717 ctx.out.sf_uauth, ctx.out.sf_uauthlen); 718 free(ctx.out.sf_path); 719 bp += used; 720 remaining -= used; 721 } 722 if (ctx.out.sf_text != NULL) { 723 used = fromright(bp, remaining, 724 STRCONSTARGS(AU_TEXT_NAME), 725 ctx.out.sf_text, ctx.out.sf_textlen); 726 free(ctx.out.sf_text); 727 bp += used; 728 remaining -= used; 729 } 730 } 731 return (rc_ret); 732 } 733 734 /* 735 * 1024 is max syslog record size, 48 is minimum header length, 736 * assuming a hostname length of 0. maxavail reduces use of the 737 * allocated space by the length of the hostname (see maxavail) 738 */ 739 #define OUTPUT_BUF_SIZE 1024 - 48 740 741 /* ARGSUSED */ 742 auditd_rc_t 743 auditd_plugin(const char *input, size_t in_len, uint32_t sequence, char **error) 744 { 745 char *outbuf; 746 auditd_rc_t rc = AUDITD_SUCCESS; 747 #if DEBUG 748 static uint32_t last_sequence = 0; 749 static uint32_t write_count = 0; 750 static uint32_t toss_count = 0; 751 752 if ((last_sequence > 0) && (sequence != last_sequence + 1)) 753 fprintf(dbfp, "syslog: buffer sequence=%d but prev=%d\n", 754 sequence, last_sequence); 755 last_sequence = sequence; 756 #endif 757 758 *error = NULL; 759 760 outbuf = malloc(OUTPUT_BUF_SIZE); 761 if (outbuf == NULL) { 762 DPRINT((dbfp, "syslog: out of memory; seq=%u\n", 763 sequence)); 764 rc = AUDITD_NO_MEMORY; 765 *error = strdup(gettext("Can't allocate buffers")); 766 } else { 767 rc = filter(input, sequence, outbuf, in_len, maxavail); 768 769 if (rc == AUDITD_SUCCESS) { 770 __audit_syslog("audit", LOG_NDELAY, 771 LOG_AUDIT, LOG_NOTICE, outbuf); 772 DPRINT((dbfp, "syslog: write_count=%u, " 773 "buffer=%u, tossed=%d\n", 774 ++write_count, sequence, toss_count)); 775 } else if (rc > 0) { /* -1 == discard it */ 776 DPRINT((dbfp, "syslog: parse failed for buffer %u\n", 777 sequence)); 778 *error = strdup(gettext( 779 "Unable to parse audit record")); 780 } else { 781 DPRINT((dbfp, "syslog: rc = %d (-1 is discard), " 782 "sequence=%u, toss_count=%d\n", 783 rc, sequence, ++toss_count)); 784 rc = 0; 785 } 786 free(outbuf); 787 } 788 return (rc); 789 } 790 791 auditd_rc_t 792 auditd_plugin_open(const kva_t *kvlist, char **ret_list, char **error) 793 { 794 char localname[MAXHOSTNAMELEN + 1]; 795 auditd_rc_t rc; 796 char *value; 797 /* kva_match doesn't do const, so copy the pointer */ 798 kva_t *kva = (kva_t *)kvlist; 799 800 *error = NULL; 801 *ret_list = NULL; 802 803 if ((kvlist == NULL) || ((value = kva_match(kva, "p_flags")) == NULL)) { 804 *error = strdup(gettext( 805 "The \"p_flags\" attribute is missing.")); 806 return (AUDITD_INVALID); 807 } 808 if (!initialized) { 809 #if DEBUG 810 dbfp = __auditd_debug_file_open(); 811 #endif 812 initialized = 1; 813 (void) pthread_mutex_init(&log_mutex, NULL); 814 /* 815 * calculate length of the local hostname for adjusting the 816 * estimate of how much space is taken by the syslog header. 817 * If the local hostname isn't available, leave some room 818 * anyway. (The -2 is for the blanks on either side of the 819 * hostname in the syslog message.) 820 */ 821 (void) pthread_mutex_lock(&log_mutex); 822 if (gethostname(localname, MAXHOSTNAMELEN)) 823 maxavail = OUTPUT_BUF_SIZE - 20; 824 else 825 maxavail = OUTPUT_BUF_SIZE - strlen(localname) - 2; 826 (void) pthread_mutex_unlock(&log_mutex); 827 828 if (init_hash(hosthash, 0, HOSTHASHSIZE, MAXHOSTNAMELEN)) 829 return (AUDITD_NO_MEMORY); 830 831 if (init_hash(uidhash, -2, UIDHASHSIZE, USERNAMELEN)) 832 return (AUDITD_NO_MEMORY); 833 834 if (init_hash(gidhash, -2, GIDHASHSIZE, GIDNAMELEN)) 835 return (AUDITD_NO_MEMORY); 836 } 837 (void) pthread_mutex_lock(&log_mutex); 838 if ((rc = setmask(value)) != AUDITD_SUCCESS) 839 *error = strdup(gettext( 840 "incorrect p_flags setting; no records will be output")); 841 842 (void) pthread_mutex_unlock(&log_mutex); 843 844 return (rc); 845 } 846 847 auditd_rc_t 848 auditd_plugin_close(char **error) 849 { 850 *error = NULL; 851 852 if (initialized) { 853 (void) pthread_mutex_destroy(&log_mutex); 854 855 free_hash(hosthash, HOSTHASHSIZE); 856 free_hash(uidhash, UIDHASHSIZE); 857 free_hash(gidhash, GIDHASHSIZE); 858 } 859 initialized = 0; 860 861 return (AUDITD_SUCCESS); 862 } 863