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