17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5c1f59b3eSpaulson * Common Development and Distribution License (the "License"). 6c1f59b3eSpaulson * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 228f775e0aSJan Friedel * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate * 257c478bd9Sstevel@tonic-gate * convert binary audit records to syslog messages and 267c478bd9Sstevel@tonic-gate * send them off to syslog 277c478bd9Sstevel@tonic-gate * 287c478bd9Sstevel@tonic-gate */ 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate /* 317c478bd9Sstevel@tonic-gate * auditd_plugin_open(), auditd_plugin() and auditd_plugin_close() 327c478bd9Sstevel@tonic-gate * implement a replacable library for use by auditd; they are a 337c478bd9Sstevel@tonic-gate * project private interface and may change without notice. 347c478bd9Sstevel@tonic-gate * 357c478bd9Sstevel@tonic-gate */ 367c478bd9Sstevel@tonic-gate #define DEBUG 0 377c478bd9Sstevel@tonic-gate #if DEBUG 38dfc7be02SJan Friedel #define DPRINT(x) { (void) fprintf x; } 397c478bd9Sstevel@tonic-gate #else 407c478bd9Sstevel@tonic-gate #define DPRINT(x) 417c478bd9Sstevel@tonic-gate #endif 427c478bd9Sstevel@tonic-gate 437c478bd9Sstevel@tonic-gate #include <arpa/inet.h> 447c478bd9Sstevel@tonic-gate #include <assert.h> 457c478bd9Sstevel@tonic-gate #include <errno.h> 467c478bd9Sstevel@tonic-gate #include <fcntl.h> 477c478bd9Sstevel@tonic-gate #include <grp.h> 487c478bd9Sstevel@tonic-gate #include <libintl.h> 497c478bd9Sstevel@tonic-gate #include <netdb.h> 507c478bd9Sstevel@tonic-gate #include <netinet/in.h> 517c478bd9Sstevel@tonic-gate #include <pthread.h> 527c478bd9Sstevel@tonic-gate #include <pwd.h> 537c478bd9Sstevel@tonic-gate #include <stdio.h> 547c478bd9Sstevel@tonic-gate #include <stdlib.h> 557c478bd9Sstevel@tonic-gate #include <string.h> 567c478bd9Sstevel@tonic-gate #include <time.h> 577c478bd9Sstevel@tonic-gate #include <syslog.h> 587c478bd9Sstevel@tonic-gate #include <sys/types.h> 597c478bd9Sstevel@tonic-gate #include <sys/socket.h> 607c478bd9Sstevel@tonic-gate #include <unistd.h> 617c478bd9Sstevel@tonic-gate 627c478bd9Sstevel@tonic-gate #include <bsm/audit.h> 637c478bd9Sstevel@tonic-gate #include <bsm/audit_record.h> 647c478bd9Sstevel@tonic-gate #include <security/auditd.h> 657c478bd9Sstevel@tonic-gate 667c478bd9Sstevel@tonic-gate #include "toktable.h" 677c478bd9Sstevel@tonic-gate #include "sysplugin.h" 687c478bd9Sstevel@tonic-gate #include "systoken.h" 697c478bd9Sstevel@tonic-gate #include <audit_plugin.h> 707c478bd9Sstevel@tonic-gate 71dfc7be02SJan Friedel /* gettext() obfuscation routine for lint */ 72dfc7be02SJan Friedel #ifdef __lint 73dfc7be02SJan Friedel #define gettext(x) x 74dfc7be02SJan Friedel #endif 75dfc7be02SJan Friedel 767c478bd9Sstevel@tonic-gate #if DEBUG 777c478bd9Sstevel@tonic-gate static FILE *dbfp; /* debug file */ 787c478bd9Sstevel@tonic-gate #endif 797c478bd9Sstevel@tonic-gate 807c478bd9Sstevel@tonic-gate extern void init_tokens(); 817c478bd9Sstevel@tonic-gate extern int parse_token(parse_context_t *); 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate static au_mask_t mask; 847c478bd9Sstevel@tonic-gate static int initialized = 0; 857c478bd9Sstevel@tonic-gate static size_t maxavail; 867c478bd9Sstevel@tonic-gate static pthread_mutex_t log_mutex; 877c478bd9Sstevel@tonic-gate 887c478bd9Sstevel@tonic-gate #define ELLIPSIS "..." 897c478bd9Sstevel@tonic-gate #define ELLIPSIS_SIZE (sizeof (ELLIPSIS) - 1) 907c478bd9Sstevel@tonic-gate 917c478bd9Sstevel@tonic-gate /* 927c478bd9Sstevel@tonic-gate * simple hashing for uid and hostname lookup 937c478bd9Sstevel@tonic-gate * 947c478bd9Sstevel@tonic-gate * performance tests showed that cacheing the hostname, uid, and gid 957c478bd9Sstevel@tonic-gate * make about a 40% difference for short audit records and regularly 967c478bd9Sstevel@tonic-gate * repeating hostname, uid, etc 977c478bd9Sstevel@tonic-gate * 987c478bd9Sstevel@tonic-gate * ht_type and ht_ip are only used for hostname lookup cacheing. 997c478bd9Sstevel@tonic-gate */ 1007c478bd9Sstevel@tonic-gate typedef struct hashtable { 1017c478bd9Sstevel@tonic-gate uint32_t ht_key; 1027c478bd9Sstevel@tonic-gate uint32_t ht_type; 1037c478bd9Sstevel@tonic-gate uint32_t ht_ip[4]; 1047c478bd9Sstevel@tonic-gate char *ht_value; 1057c478bd9Sstevel@tonic-gate size_t ht_length; 1067c478bd9Sstevel@tonic-gate } hashtable_t; 1077c478bd9Sstevel@tonic-gate #define HOSTHASHSIZE 128 1087c478bd9Sstevel@tonic-gate #define UIDHASHSIZE 128 1097c478bd9Sstevel@tonic-gate #define GIDHASHSIZE 32 1107c478bd9Sstevel@tonic-gate 1117c478bd9Sstevel@tonic-gate static hashtable_t uidhash[UIDHASHSIZE]; 1127c478bd9Sstevel@tonic-gate static hashtable_t gidhash[GIDHASHSIZE]; 1137c478bd9Sstevel@tonic-gate static hashtable_t hosthash[HOSTHASHSIZE]; 1147c478bd9Sstevel@tonic-gate 1157c478bd9Sstevel@tonic-gate #define STRCONSTARGS(s) (s), (sizeof (s) - 1) 1167c478bd9Sstevel@tonic-gate /* 1177c478bd9Sstevel@tonic-gate * the hash "handles" collisions by overwriting the old 1187c478bd9Sstevel@tonic-gate * hash entry with the new. Perfection is not the goal. 1197c478bd9Sstevel@tonic-gate * 1207c478bd9Sstevel@tonic-gate * the key (s) is a 32 bit integer, handled here as 1217c478bd9Sstevel@tonic-gate * four bytes. If the hash size is increased beyond 1227c478bd9Sstevel@tonic-gate * 256, this macro will need some work. 1237c478bd9Sstevel@tonic-gate */ 1247c478bd9Sstevel@tonic-gate #define HASH(s, r, m) {\ 1257c478bd9Sstevel@tonic-gate uint32_t _mush = 0;\ 1267c478bd9Sstevel@tonic-gate int _i;\ 1277c478bd9Sstevel@tonic-gate for (_i = 0; _i < 4; _i++) {\ 1287c478bd9Sstevel@tonic-gate _mush ^= *(s)++;\ 1297c478bd9Sstevel@tonic-gate }\ 1307c478bd9Sstevel@tonic-gate r = _mush % m;\ 1317c478bd9Sstevel@tonic-gate } 1327c478bd9Sstevel@tonic-gate 1337c478bd9Sstevel@tonic-gate 1347c478bd9Sstevel@tonic-gate /* 1357c478bd9Sstevel@tonic-gate * The default mask for sysplugin is to reject all record types. 1367c478bd9Sstevel@tonic-gate * The parameters input here select which classes to allow. 1377c478bd9Sstevel@tonic-gate * 1387c478bd9Sstevel@tonic-gate * getauditflgsbin() outputs error messages to syslog. 1397c478bd9Sstevel@tonic-gate * 1407c478bd9Sstevel@tonic-gate * caller must hold log_mutex 1417c478bd9Sstevel@tonic-gate */ 1427c478bd9Sstevel@tonic-gate 1437c478bd9Sstevel@tonic-gate static auditd_rc_t 1447c478bd9Sstevel@tonic-gate setmask(const char *flags) 1457c478bd9Sstevel@tonic-gate { 1467c478bd9Sstevel@tonic-gate au_mask_t tmask; 1477c478bd9Sstevel@tonic-gate char *input, *ip, c; 1487c478bd9Sstevel@tonic-gate auditd_rc_t rc = AUDITD_SUCCESS; 1497c478bd9Sstevel@tonic-gate 1507c478bd9Sstevel@tonic-gate mask.am_success = 0x0; 1517c478bd9Sstevel@tonic-gate mask.am_failure = 0x0; 1527c478bd9Sstevel@tonic-gate 1537c478bd9Sstevel@tonic-gate if (flags != NULL) { 1547c478bd9Sstevel@tonic-gate /* 1557c478bd9Sstevel@tonic-gate * getauditflagsbin doesn't like blanks, but admins do 1567c478bd9Sstevel@tonic-gate */ 1577c478bd9Sstevel@tonic-gate input = malloc(strlen(flags) + 1); 1587c478bd9Sstevel@tonic-gate if (input == NULL) 1597c478bd9Sstevel@tonic-gate return (AUDITD_NO_MEMORY); 1607c478bd9Sstevel@tonic-gate 1617c478bd9Sstevel@tonic-gate ip = input; 1627c478bd9Sstevel@tonic-gate 1637c478bd9Sstevel@tonic-gate for (; (c = *flags) != '\0'; flags++) { 1647c478bd9Sstevel@tonic-gate if (c == ' ') 1657c478bd9Sstevel@tonic-gate continue; 1667c478bd9Sstevel@tonic-gate *ip++ = c; 1677c478bd9Sstevel@tonic-gate } 1687c478bd9Sstevel@tonic-gate *ip = '\0'; 1697c478bd9Sstevel@tonic-gate if (getauditflagsbin(input, &tmask) == 0) { 1707c478bd9Sstevel@tonic-gate mask.am_success |= tmask.am_success; 1717c478bd9Sstevel@tonic-gate mask.am_failure |= tmask.am_failure; 1727c478bd9Sstevel@tonic-gate } 1737c478bd9Sstevel@tonic-gate } 1747c478bd9Sstevel@tonic-gate if ((mask.am_success | mask.am_failure) == 0) { 1757c478bd9Sstevel@tonic-gate rc = AUDITD_INVALID; 1767c478bd9Sstevel@tonic-gate __audit_syslog("audit_syslog.so", LOG_CONS | LOG_NDELAY, 1777c478bd9Sstevel@tonic-gate LOG_DAEMON, LOG_ERR, 1787c478bd9Sstevel@tonic-gate gettext("plugin is configured with empty class mask\n")); 1797c478bd9Sstevel@tonic-gate } 1807c478bd9Sstevel@tonic-gate free(input); 1817c478bd9Sstevel@tonic-gate return (rc); 1827c478bd9Sstevel@tonic-gate } 1837c478bd9Sstevel@tonic-gate 1847c478bd9Sstevel@tonic-gate /* 1857c478bd9Sstevel@tonic-gate * based on the current value of mask, either keep or toss the 1867c478bd9Sstevel@tonic-gate * current audit record. The input is 1 for success, -1 for 1877c478bd9Sstevel@tonic-gate * failure. 0 means no exit or return token was seen. 1887c478bd9Sstevel@tonic-gate * 1897c478bd9Sstevel@tonic-gate * au_preselect returns 1 for keep it, 0 for delete it, and 1907c478bd9Sstevel@tonic-gate * -1 for some sort of error. Here, 1 and -1 are considered 1917c478bd9Sstevel@tonic-gate * equivalent. tossit() returns 1 for delete it and 0 for 1927c478bd9Sstevel@tonic-gate * keep it. 1937c478bd9Sstevel@tonic-gate */ 1947c478bd9Sstevel@tonic-gate 1957c478bd9Sstevel@tonic-gate static int 1967c478bd9Sstevel@tonic-gate tossit(au_event_t id, int passfail) 1977c478bd9Sstevel@tonic-gate { 1987c478bd9Sstevel@tonic-gate int rc; 1997c478bd9Sstevel@tonic-gate int selFlag; 2007c478bd9Sstevel@tonic-gate 2017c478bd9Sstevel@tonic-gate switch (passfail) { 2027c478bd9Sstevel@tonic-gate case 1: 2037c478bd9Sstevel@tonic-gate selFlag = AU_PRS_SUCCESS; 2047c478bd9Sstevel@tonic-gate break; 2057c478bd9Sstevel@tonic-gate case -1: 2067c478bd9Sstevel@tonic-gate selFlag = AU_PRS_FAILURE; 2077c478bd9Sstevel@tonic-gate break; 2087c478bd9Sstevel@tonic-gate default: /* no exit or return token */ 2097c478bd9Sstevel@tonic-gate selFlag = AU_PRS_BOTH; 2107c478bd9Sstevel@tonic-gate break; 2117c478bd9Sstevel@tonic-gate } 2127c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&log_mutex); 2137c478bd9Sstevel@tonic-gate rc = au_preselect(id, &mask, selFlag, AU_PRS_USECACHE); 2147c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&log_mutex); 2157c478bd9Sstevel@tonic-gate 2167c478bd9Sstevel@tonic-gate return (rc == 0); 2177c478bd9Sstevel@tonic-gate } 2187c478bd9Sstevel@tonic-gate 2197c478bd9Sstevel@tonic-gate /* 2207c478bd9Sstevel@tonic-gate * the three bytes for ellipsis could potentially be longer than the 2217c478bd9Sstevel@tonic-gate * space available for text if maxavail is within two bytes of 2227c478bd9Sstevel@tonic-gate * OUTPUT_BUF_SIZE, which can happen if the hostname is one or two 2237c478bd9Sstevel@tonic-gate * characters long. If there isn't room for ellipsis, there isn't 2247c478bd9Sstevel@tonic-gate * room for the data, so it is simply dropped. 2257c478bd9Sstevel@tonic-gate */ 2267c478bd9Sstevel@tonic-gate 2277c478bd9Sstevel@tonic-gate static size_t 2287c478bd9Sstevel@tonic-gate fromleft(char *p, size_t avail, char *attrname, size_t attrlen, char *txt, 2297c478bd9Sstevel@tonic-gate size_t txtlen) 2307c478bd9Sstevel@tonic-gate { 2317c478bd9Sstevel@tonic-gate size_t len; 2327c478bd9Sstevel@tonic-gate 2337c478bd9Sstevel@tonic-gate if (avail < attrlen + ELLIPSIS_SIZE) 2347c478bd9Sstevel@tonic-gate return (0); 2357c478bd9Sstevel@tonic-gate 2367c478bd9Sstevel@tonic-gate (void) memcpy(p, attrname, attrlen); 2377c478bd9Sstevel@tonic-gate p += attrlen; 2387c478bd9Sstevel@tonic-gate avail -= attrlen; 2397c478bd9Sstevel@tonic-gate if (txtlen > avail) { 2407c478bd9Sstevel@tonic-gate (void) memcpy(p, ELLIPSIS, ELLIPSIS_SIZE); 2417c478bd9Sstevel@tonic-gate txt += txtlen - (avail - ELLIPSIS_SIZE); 2427c478bd9Sstevel@tonic-gate (void) memcpy(p + ELLIPSIS_SIZE, txt, avail - ELLIPSIS_SIZE); 2437c478bd9Sstevel@tonic-gate len = attrlen + avail; 2447c478bd9Sstevel@tonic-gate p += avail; 2457c478bd9Sstevel@tonic-gate } else { 2467c478bd9Sstevel@tonic-gate (void) memcpy(p, txt, txtlen); 2477c478bd9Sstevel@tonic-gate len = attrlen + txtlen; 2487c478bd9Sstevel@tonic-gate p += txtlen; 2497c478bd9Sstevel@tonic-gate } 2507c478bd9Sstevel@tonic-gate *p = '\0'; 2517c478bd9Sstevel@tonic-gate return (len); 2527c478bd9Sstevel@tonic-gate } 2537c478bd9Sstevel@tonic-gate 2547c478bd9Sstevel@tonic-gate static size_t 2557c478bd9Sstevel@tonic-gate fromright(char *p, size_t avail, char *attrname, size_t attrlen, char *txt, 2567c478bd9Sstevel@tonic-gate size_t txtlen) 2577c478bd9Sstevel@tonic-gate { 2587c478bd9Sstevel@tonic-gate size_t len; 2597c478bd9Sstevel@tonic-gate 2607c478bd9Sstevel@tonic-gate if (avail < attrlen + ELLIPSIS_SIZE) 2617c478bd9Sstevel@tonic-gate return (0); 2627c478bd9Sstevel@tonic-gate 2637c478bd9Sstevel@tonic-gate (void) memcpy(p, attrname, attrlen); 2647c478bd9Sstevel@tonic-gate p += attrlen; 2657c478bd9Sstevel@tonic-gate avail -= attrlen; 2667c478bd9Sstevel@tonic-gate if (txtlen > avail) { 2677c478bd9Sstevel@tonic-gate (void) memcpy(p, txt, avail - ELLIPSIS_SIZE); 2687c478bd9Sstevel@tonic-gate (void) memcpy(p + (avail - ELLIPSIS_SIZE), 2697c478bd9Sstevel@tonic-gate ELLIPSIS, ELLIPSIS_SIZE); 2707c478bd9Sstevel@tonic-gate len = attrlen + avail; 2717c478bd9Sstevel@tonic-gate p += avail; 2727c478bd9Sstevel@tonic-gate } else { 2737c478bd9Sstevel@tonic-gate (void) memcpy(p, txt, txtlen); 2747c478bd9Sstevel@tonic-gate p += txtlen; 2757c478bd9Sstevel@tonic-gate len = attrlen + txtlen; 2767c478bd9Sstevel@tonic-gate } 2777c478bd9Sstevel@tonic-gate *p = '\0'; 2787c478bd9Sstevel@tonic-gate return (len); 2797c478bd9Sstevel@tonic-gate } 2807c478bd9Sstevel@tonic-gate 2817c478bd9Sstevel@tonic-gate static int 2827c478bd9Sstevel@tonic-gate init_hash(hashtable_t *table, int bad_key, int table_length, 2837c478bd9Sstevel@tonic-gate size_t max_value) 2847c478bd9Sstevel@tonic-gate { 2857c478bd9Sstevel@tonic-gate int i; 2867c478bd9Sstevel@tonic-gate 2877c478bd9Sstevel@tonic-gate for (i = 0; i < table_length; i++) { 2887c478bd9Sstevel@tonic-gate table[i].ht_value = malloc(max_value + 1); 2897c478bd9Sstevel@tonic-gate table[i].ht_key = bad_key; 2907c478bd9Sstevel@tonic-gate table[i].ht_length = 0; 2917c478bd9Sstevel@tonic-gate if (table[i].ht_value == NULL) { 2927c478bd9Sstevel@tonic-gate int j; 2937c478bd9Sstevel@tonic-gate for (j = 0; j < i; j++) 2947c478bd9Sstevel@tonic-gate free(table[j].ht_value); 2957c478bd9Sstevel@tonic-gate return (-1); 2967c478bd9Sstevel@tonic-gate } 2977c478bd9Sstevel@tonic-gate *(table[i].ht_value) = '\0'; 2987c478bd9Sstevel@tonic-gate } 2997c478bd9Sstevel@tonic-gate return (0); 3007c478bd9Sstevel@tonic-gate } 3017c478bd9Sstevel@tonic-gate 3027c478bd9Sstevel@tonic-gate static void 3037c478bd9Sstevel@tonic-gate free_hash(hashtable_t *table, int table_length) 3047c478bd9Sstevel@tonic-gate { 3057c478bd9Sstevel@tonic-gate int i; 3067c478bd9Sstevel@tonic-gate 3077c478bd9Sstevel@tonic-gate for (i = 0; i < table_length; i++) { 3087c478bd9Sstevel@tonic-gate free(table[i].ht_value); 3097c478bd9Sstevel@tonic-gate } 3107c478bd9Sstevel@tonic-gate } 3117c478bd9Sstevel@tonic-gate 3127c478bd9Sstevel@tonic-gate 3137c478bd9Sstevel@tonic-gate /* 3147c478bd9Sstevel@tonic-gate * do IP -> hostname lookup 3157c478bd9Sstevel@tonic-gate */ 3167c478bd9Sstevel@tonic-gate #define UNKNOWN "unknown" 3177c478bd9Sstevel@tonic-gate #define UNKNOWN_LEN (sizeof (UNKNOWN)) 3187c478bd9Sstevel@tonic-gate 3197c478bd9Sstevel@tonic-gate static size_t 3207c478bd9Sstevel@tonic-gate gethname(au_tid_addr_t *tid, char *p, size_t max, char *prefix, 3217c478bd9Sstevel@tonic-gate size_t prefix_len) 3227c478bd9Sstevel@tonic-gate { 3237c478bd9Sstevel@tonic-gate size_t len, l; 3247c478bd9Sstevel@tonic-gate struct hostent *host; 3257c478bd9Sstevel@tonic-gate int rc; 3267c478bd9Sstevel@tonic-gate int af; 3277c478bd9Sstevel@tonic-gate int ix; 3287c478bd9Sstevel@tonic-gate char *hash_key; 3297c478bd9Sstevel@tonic-gate uint32_t key; 3307c478bd9Sstevel@tonic-gate int match; 3317c478bd9Sstevel@tonic-gate 3327c478bd9Sstevel@tonic-gate if (prefix_len > max) 3337c478bd9Sstevel@tonic-gate return (0); 3347c478bd9Sstevel@tonic-gate 3357c478bd9Sstevel@tonic-gate (void) memcpy(p, prefix, prefix_len); 3367c478bd9Sstevel@tonic-gate p += prefix_len; 3377c478bd9Sstevel@tonic-gate max -= prefix_len; 3387c478bd9Sstevel@tonic-gate 3397c478bd9Sstevel@tonic-gate if (tid->at_type == AU_IPv6) { 3407c478bd9Sstevel@tonic-gate key = tid->at_addr[0] ^ 3418f775e0aSJan Friedel tid->at_addr[1] ^ 3428f775e0aSJan Friedel tid->at_addr[2] ^ 3438f775e0aSJan Friedel tid->at_addr[3]; 3447c478bd9Sstevel@tonic-gate } else 3457c478bd9Sstevel@tonic-gate key = (tid->at_addr[0]); 3467c478bd9Sstevel@tonic-gate 3477c478bd9Sstevel@tonic-gate hash_key = (char *)&key; 3487c478bd9Sstevel@tonic-gate 3497c478bd9Sstevel@tonic-gate HASH(hash_key, ix, HOSTHASHSIZE); 3507c478bd9Sstevel@tonic-gate 3517c478bd9Sstevel@tonic-gate match = 0; 3527c478bd9Sstevel@tonic-gate 3537c478bd9Sstevel@tonic-gate if (key == 0) { 3547c478bd9Sstevel@tonic-gate l = UNKNOWN_LEN; /* includes end of string */ 3557c478bd9Sstevel@tonic-gate if (l > max) 3567c478bd9Sstevel@tonic-gate l = max; 3577c478bd9Sstevel@tonic-gate len = prefix_len + strlcpy(p, UNKNOWN, l); 3587c478bd9Sstevel@tonic-gate return (len); 3597c478bd9Sstevel@tonic-gate } 3607c478bd9Sstevel@tonic-gate 3617c478bd9Sstevel@tonic-gate if (tid->at_type == AU_IPv6) { 3627c478bd9Sstevel@tonic-gate if ((key == hosthash[ix].ht_key) && 3637c478bd9Sstevel@tonic-gate (hosthash[ix].ht_type == tid->at_type)) { 3647c478bd9Sstevel@tonic-gate int i; 3657c478bd9Sstevel@tonic-gate match = 1; 3667c478bd9Sstevel@tonic-gate for (i = 0; i < 4; i++) { 3677c478bd9Sstevel@tonic-gate if (hosthash[ix].ht_ip[i] != tid->at_addr[i]) { 3687c478bd9Sstevel@tonic-gate match = 0; 3697c478bd9Sstevel@tonic-gate break; 3707c478bd9Sstevel@tonic-gate } 3717c478bd9Sstevel@tonic-gate } 3727c478bd9Sstevel@tonic-gate } 3737c478bd9Sstevel@tonic-gate } else if (key == hosthash[ix].ht_key) { 3747c478bd9Sstevel@tonic-gate match = 1; 3757c478bd9Sstevel@tonic-gate } 3767c478bd9Sstevel@tonic-gate if (!match) { 3777c478bd9Sstevel@tonic-gate hosthash[ix].ht_key = key; 3787c478bd9Sstevel@tonic-gate hosthash[ix].ht_type = tid->at_type; 3797c478bd9Sstevel@tonic-gate 3807c478bd9Sstevel@tonic-gate if (tid->at_type == AU_IPv4) { 3817c478bd9Sstevel@tonic-gate hosthash[ix].ht_ip[0] = tid->at_addr[0]; 3827c478bd9Sstevel@tonic-gate af = AF_INET; 3837c478bd9Sstevel@tonic-gate } else { 3847c478bd9Sstevel@tonic-gate (void) memcpy((char *)hosthash[ix].ht_ip, 3857c478bd9Sstevel@tonic-gate (char *)tid->at_addr, AU_IPv6); 3867c478bd9Sstevel@tonic-gate af = AF_INET6; 3877c478bd9Sstevel@tonic-gate } 3887c478bd9Sstevel@tonic-gate host = getipnodebyaddr((const void *)tid->at_addr, 3897c478bd9Sstevel@tonic-gate tid->at_type, af, &rc); 3907c478bd9Sstevel@tonic-gate 3917c478bd9Sstevel@tonic-gate if (host == NULL) { 3927c478bd9Sstevel@tonic-gate (void) inet_ntop(af, (void *)tid->at_addr, 3937c478bd9Sstevel@tonic-gate hosthash[ix].ht_value, MAXHOSTNAMELEN); 3947c478bd9Sstevel@tonic-gate hosthash[ix].ht_length = strlen(hosthash[ix].ht_value); 3957c478bd9Sstevel@tonic-gate } else { 3967c478bd9Sstevel@tonic-gate hosthash[ix].ht_length = strlcpy(hosthash[ix].ht_value, 3977c478bd9Sstevel@tonic-gate host->h_name, MAXHOSTNAMELEN); 3987c478bd9Sstevel@tonic-gate freehostent(host); 3997c478bd9Sstevel@tonic-gate } 4007c478bd9Sstevel@tonic-gate } 4017c478bd9Sstevel@tonic-gate l = hosthash[ix].ht_length + 1; 4027c478bd9Sstevel@tonic-gate if (l > max) 4037c478bd9Sstevel@tonic-gate l = max; 4047c478bd9Sstevel@tonic-gate 4057c478bd9Sstevel@tonic-gate len = prefix_len + strlcpy(p, hosthash[ix].ht_value, l); 4067c478bd9Sstevel@tonic-gate 4077c478bd9Sstevel@tonic-gate return (len); 4087c478bd9Sstevel@tonic-gate } 4097c478bd9Sstevel@tonic-gate /* 4107c478bd9Sstevel@tonic-gate * the appropriate buffer length for getpwuid_r() isn't documented; 4117c478bd9Sstevel@tonic-gate * 1024 should be enough. 4127c478bd9Sstevel@tonic-gate */ 4137c478bd9Sstevel@tonic-gate #define GETPWUID_BUFF_LEN 1024 4147c478bd9Sstevel@tonic-gate #define USERNAMELEN 256 4157c478bd9Sstevel@tonic-gate #define GIDNAMELEN 256 4167c478bd9Sstevel@tonic-gate 4177c478bd9Sstevel@tonic-gate static size_t 4187c478bd9Sstevel@tonic-gate getuname(uid_t uid, gid_t gid, char *p, size_t max, char *prefix, 4197c478bd9Sstevel@tonic-gate size_t prefix_len) 4207c478bd9Sstevel@tonic-gate { 4217c478bd9Sstevel@tonic-gate struct passwd pw; 4227c478bd9Sstevel@tonic-gate char pw_buf[GETPWUID_BUFF_LEN]; 4237c478bd9Sstevel@tonic-gate size_t len, l; 4247c478bd9Sstevel@tonic-gate struct group gr; 4257c478bd9Sstevel@tonic-gate int ix; 4267c478bd9Sstevel@tonic-gate char *hash_key; 4277c478bd9Sstevel@tonic-gate 4287c478bd9Sstevel@tonic-gate if (prefix_len > max) 4297c478bd9Sstevel@tonic-gate return (0); 4307c478bd9Sstevel@tonic-gate 4317c478bd9Sstevel@tonic-gate len = prefix_len; 4327c478bd9Sstevel@tonic-gate 4337c478bd9Sstevel@tonic-gate (void) memcpy(p, prefix, len); 4347c478bd9Sstevel@tonic-gate p += len; 4357c478bd9Sstevel@tonic-gate max -= len; 4367c478bd9Sstevel@tonic-gate 4377c478bd9Sstevel@tonic-gate hash_key = (char *)&uid; 4387c478bd9Sstevel@tonic-gate 4397c478bd9Sstevel@tonic-gate HASH(hash_key, ix, UIDHASHSIZE); 4407c478bd9Sstevel@tonic-gate 4417c478bd9Sstevel@tonic-gate if (uid != uidhash[ix].ht_key) { 4427c478bd9Sstevel@tonic-gate uidhash[ix].ht_key = uid; 4437c478bd9Sstevel@tonic-gate 4447c478bd9Sstevel@tonic-gate if ((getpwuid_r(uid, &pw, pw_buf, GETPWUID_BUFF_LEN)) == NULL) 4457c478bd9Sstevel@tonic-gate l = snprintf(uidhash[ix].ht_value, USERNAMELEN, 4467c478bd9Sstevel@tonic-gate "%d", uid); 4477c478bd9Sstevel@tonic-gate else 4487c478bd9Sstevel@tonic-gate l = strlcpy(uidhash[ix].ht_value, pw.pw_name, 4497c478bd9Sstevel@tonic-gate USERNAMELEN); 4507c478bd9Sstevel@tonic-gate 4517c478bd9Sstevel@tonic-gate uidhash[ix].ht_length = l; 4527c478bd9Sstevel@tonic-gate } 4537c478bd9Sstevel@tonic-gate l = uidhash[ix].ht_length + 1; 4547c478bd9Sstevel@tonic-gate if (l > max) 4557c478bd9Sstevel@tonic-gate l = max; 4567c478bd9Sstevel@tonic-gate (void) memcpy(p, uidhash[ix].ht_value, l); 4577c478bd9Sstevel@tonic-gate len += l - 1; 4587c478bd9Sstevel@tonic-gate 459f48205beScasper if (gid != (gid_t)-2) { 4607c478bd9Sstevel@tonic-gate p += l - 1; 4617c478bd9Sstevel@tonic-gate max -= l - 1; 4627c478bd9Sstevel@tonic-gate if (max < 2) 4637c478bd9Sstevel@tonic-gate return (len); 4647c478bd9Sstevel@tonic-gate 4657c478bd9Sstevel@tonic-gate hash_key = (char *)&gid; 4667c478bd9Sstevel@tonic-gate HASH(hash_key, ix, GIDHASHSIZE); 4677c478bd9Sstevel@tonic-gate 4687c478bd9Sstevel@tonic-gate if (gid != gidhash[ix].ht_key) { 4697c478bd9Sstevel@tonic-gate gidhash[ix].ht_key = gid; 4707c478bd9Sstevel@tonic-gate 4717c478bd9Sstevel@tonic-gate if (getgrgid_r(gid, &gr, pw_buf, GETPWUID_BUFF_LEN) == 4727c478bd9Sstevel@tonic-gate NULL) 4737c478bd9Sstevel@tonic-gate gidhash[ix].ht_length = 4747c478bd9Sstevel@tonic-gate snprintf(gidhash[ix].ht_value, GIDNAMELEN, 4758f775e0aSJan Friedel "%d", gid); 4767c478bd9Sstevel@tonic-gate else 4777c478bd9Sstevel@tonic-gate gidhash[ix].ht_length = 4787c478bd9Sstevel@tonic-gate strlcpy(gidhash[ix].ht_value, 4797c478bd9Sstevel@tonic-gate gr.gr_name, GIDNAMELEN); 4807c478bd9Sstevel@tonic-gate } 4817c478bd9Sstevel@tonic-gate *p++ = ':'; 4827c478bd9Sstevel@tonic-gate len++; 4837c478bd9Sstevel@tonic-gate max--; 4847c478bd9Sstevel@tonic-gate 4857c478bd9Sstevel@tonic-gate l = gidhash[ix].ht_length + 1; 4867c478bd9Sstevel@tonic-gate if (l > max) 4877c478bd9Sstevel@tonic-gate l = max; 4887c478bd9Sstevel@tonic-gate (void) memcpy(p, gidhash[ix].ht_value, l); 4897c478bd9Sstevel@tonic-gate len += l - 1; 4907c478bd9Sstevel@tonic-gate } 4917c478bd9Sstevel@tonic-gate return (len); 4927c478bd9Sstevel@tonic-gate } 4937c478bd9Sstevel@tonic-gate 4947c478bd9Sstevel@tonic-gate /* 4957c478bd9Sstevel@tonic-gate * filter() parse input; toss if not wanted. 4967c478bd9Sstevel@tonic-gate * 4977c478bd9Sstevel@tonic-gate * the input value sequence is a number generated when the buffer 4987c478bd9Sstevel@tonic-gate * was queued. ctx.out.sf_sequence, if not -1, is the sequence number 4997c478bd9Sstevel@tonic-gate * generated in c2audit. It is not part of the "official" syslog 5007c478bd9Sstevel@tonic-gate * output but is included if DEBUG is on. 5017c478bd9Sstevel@tonic-gate */ 5027c478bd9Sstevel@tonic-gate #define EVENT_NAME_LEN 32 5037c478bd9Sstevel@tonic-gate 5047c478bd9Sstevel@tonic-gate static auditd_rc_t 5058f775e0aSJan Friedel filter(const char *input, uint64_t sequence, char *output, 5067c478bd9Sstevel@tonic-gate size_t in_len, size_t out_len) 5077c478bd9Sstevel@tonic-gate { 5087c478bd9Sstevel@tonic-gate parse_context_t ctx; 5097c478bd9Sstevel@tonic-gate char *bp; 5107c478bd9Sstevel@tonic-gate auditd_rc_t rc = AUDITD_SUCCESS; 5117c478bd9Sstevel@tonic-gate auditd_rc_t rc_ret = AUDITD_SUCCESS; 5127c478bd9Sstevel@tonic-gate size_t used, remaining; 5137c478bd9Sstevel@tonic-gate char *last_adr; /* infinite loop check */ 5147c478bd9Sstevel@tonic-gate int token_count = 0; 5157c478bd9Sstevel@tonic-gate int parse_rc; 5167c478bd9Sstevel@tonic-gate 5177c478bd9Sstevel@tonic-gate static parse_context_t initial_ctx; 5187c478bd9Sstevel@tonic-gate static int first = 1; 5197c478bd9Sstevel@tonic-gate 5207c478bd9Sstevel@tonic-gate if (first) { 5217c478bd9Sstevel@tonic-gate first = 0; 5227c478bd9Sstevel@tonic-gate 523c1f59b3eSpaulson /* 524c1f59b3eSpaulson * Any member or submember of parse_context_t which utilizes 525c1f59b3eSpaulson * allocated memory must free() the memory after calling 526c1f59b3eSpaulson * parse_token() for both the preselected and non-preselected 527c1f59b3eSpaulson * cases. 528c1f59b3eSpaulson * New additions to parse_context_t or its submembers need to 529c1f59b3eSpaulson * have this same treatment. 530c1f59b3eSpaulson */ 5317c478bd9Sstevel@tonic-gate initial_ctx.out.sf_eventid = 0; 5327c478bd9Sstevel@tonic-gate initial_ctx.out.sf_reclen = 0; 5337c478bd9Sstevel@tonic-gate initial_ctx.out.sf_pass = 0; 5347c478bd9Sstevel@tonic-gate initial_ctx.out.sf_asid = 0; 535f48205beScasper initial_ctx.out.sf_auid = (uid_t)-2; 536f48205beScasper initial_ctx.out.sf_euid = (uid_t)-2; 537f48205beScasper initial_ctx.out.sf_egid = (gid_t)-2; 5387c478bd9Sstevel@tonic-gate initial_ctx.out.sf_tid.at_type = 0; 539f48205beScasper initial_ctx.out.sf_pauid = (uid_t)-2; 540*2967b05aSJan Friedel initial_ctx.out.sf_peuid = (uid_t)-2; 5417c478bd9Sstevel@tonic-gate initial_ctx.out.sf_uauthlen = 0; 5427c478bd9Sstevel@tonic-gate initial_ctx.out.sf_uauth = NULL; 5437c478bd9Sstevel@tonic-gate initial_ctx.out.sf_pathlen = 0; 5447c478bd9Sstevel@tonic-gate initial_ctx.out.sf_path = NULL; 5457c478bd9Sstevel@tonic-gate initial_ctx.out.sf_atpathlen = 0; 5467c478bd9Sstevel@tonic-gate initial_ctx.out.sf_atpath = NULL; 5477c478bd9Sstevel@tonic-gate initial_ctx.out.sf_textlen = 0; 5487c478bd9Sstevel@tonic-gate initial_ctx.out.sf_text = NULL; 5497c478bd9Sstevel@tonic-gate initial_ctx.out.sf_sequence = -1; 5507c478bd9Sstevel@tonic-gate initial_ctx.out.sf_zonelen = 0; 5517c478bd9Sstevel@tonic-gate initial_ctx.out.sf_zonename = NULL; 5527c478bd9Sstevel@tonic-gate 5537c478bd9Sstevel@tonic-gate init_tokens(); /* cmd/praudit/toktable.c */ 5547c478bd9Sstevel@tonic-gate } 5557c478bd9Sstevel@tonic-gate (void) memcpy(&ctx, &initial_ctx, sizeof (parse_context_t)); 5567c478bd9Sstevel@tonic-gate ctx.id = sequence; 5577c478bd9Sstevel@tonic-gate ctx.adr.adr_stream = (char *)input; 5587c478bd9Sstevel@tonic-gate ctx.adr.adr_now = (char *)input; 5597c478bd9Sstevel@tonic-gate 5607c478bd9Sstevel@tonic-gate last_adr = NULL; 5617c478bd9Sstevel@tonic-gate while ((ctx.adr.adr_now - ctx.adr.adr_stream) < in_len) { 5627c478bd9Sstevel@tonic-gate assert(last_adr != ctx.adr.adr_now); 5637c478bd9Sstevel@tonic-gate token_count++; 5647c478bd9Sstevel@tonic-gate last_adr = ctx.adr.adr_now; 5657c478bd9Sstevel@tonic-gate if ((parse_rc = parse_token(&ctx)) != 0) { 5667c478bd9Sstevel@tonic-gate char message[256]; 5677c478bd9Sstevel@tonic-gate au_event_ent_t *event; 5687c478bd9Sstevel@tonic-gate char event_name[EVENT_NAME_LEN]; 5697c478bd9Sstevel@tonic-gate char sequence_str[EVENT_NAME_LEN]; 5707c478bd9Sstevel@tonic-gate 5717c478bd9Sstevel@tonic-gate if (cacheauevent(&event, ctx.out.sf_eventid) < 0) 5727c478bd9Sstevel@tonic-gate (void) snprintf(event_name, EVENT_NAME_LEN, 573d0fa49b7STony Nguyen "%hu", ctx.out.sf_eventid); 5747c478bd9Sstevel@tonic-gate else 5757c478bd9Sstevel@tonic-gate (void) strlcpy(event_name, event->ae_desc, 5767c478bd9Sstevel@tonic-gate EVENT_NAME_LEN); 5777c478bd9Sstevel@tonic-gate 5787c478bd9Sstevel@tonic-gate if (token_count < 2) 5797c478bd9Sstevel@tonic-gate /* leave rc_ret unchanged */ 5807c478bd9Sstevel@tonic-gate rc = AUDITD_INVALID; 5817c478bd9Sstevel@tonic-gate 5827c478bd9Sstevel@tonic-gate if (ctx.out.sf_sequence != -1) 5837c478bd9Sstevel@tonic-gate (void) snprintf(sequence_str, EVENT_NAME_LEN, 5847c478bd9Sstevel@tonic-gate " (seq=%u) ", ctx.out.sf_sequence); 5857c478bd9Sstevel@tonic-gate else 5867c478bd9Sstevel@tonic-gate sequence_str[0] = '\0'; 5877c478bd9Sstevel@tonic-gate 5887c478bd9Sstevel@tonic-gate (void) snprintf(message, 256, 5897c478bd9Sstevel@tonic-gate gettext("error before token %d (previous token=%d)" 5907c478bd9Sstevel@tonic-gate " of record type %s%s\n"), 5917c478bd9Sstevel@tonic-gate token_count, parse_rc, event_name, sequence_str); 5927c478bd9Sstevel@tonic-gate 593dfc7be02SJan Friedel #if DEBUG 594dfc7be02SJan Friedel /*LINTED*/ 595dfc7be02SJan Friedel (void) fprintf(dbfp, message); 596dfc7be02SJan Friedel #endif 5977c478bd9Sstevel@tonic-gate 5987c478bd9Sstevel@tonic-gate __audit_syslog("audit_syslog.so", 5997c478bd9Sstevel@tonic-gate LOG_PID | LOG_ODELAY | LOG_CONS, 6007c478bd9Sstevel@tonic-gate LOG_DAEMON, LOG_ALERT, message); 6017c478bd9Sstevel@tonic-gate break; 6027c478bd9Sstevel@tonic-gate } 6037c478bd9Sstevel@tonic-gate } 6047c478bd9Sstevel@tonic-gate if (rc == AUDITD_SUCCESS) { 6057c478bd9Sstevel@tonic-gate if (tossit(ctx.out.sf_eventid, ctx.out.sf_pass)) { 6067c478bd9Sstevel@tonic-gate #if DEBUG 6077c478bd9Sstevel@tonic-gate if (ctx.out.sf_sequence != -1) 608dfc7be02SJan Friedel (void) fprintf(dbfp, 609d0fa49b7STony Nguyen "syslog tossed (event=%hu) record %u " 6108f775e0aSJan Friedel "/ buffer %llu\n", 6117c478bd9Sstevel@tonic-gate ctx.out.sf_eventid, ctx.out.sf_sequence, 6127c478bd9Sstevel@tonic-gate sequence); 6137c478bd9Sstevel@tonic-gate else 614dfc7be02SJan Friedel (void) fprintf(dbfp, 6158f775e0aSJan Friedel "syslog tossed (event=%hu) buffer %llu\n", 6167c478bd9Sstevel@tonic-gate ctx.out.sf_eventid, sequence); 6177c478bd9Sstevel@tonic-gate #endif 618c1f59b3eSpaulson 619c1f59b3eSpaulson /* 620c1f59b3eSpaulson * Members or submembers of parse_context_t which 621c1f59b3eSpaulson * utilize allocated memory need to free() the memory 622c1f59b3eSpaulson * here to handle the case of not being preselected as 623c1f59b3eSpaulson * well as below for when the event is preselected. 624c1f59b3eSpaulson * New additions to parse_context_t or any of its 625c1f59b3eSpaulson * submembers need to get the same treatment. 626c1f59b3eSpaulson */ 627c1f59b3eSpaulson if (ctx.out.sf_uauthlen > 0) { 628c1f59b3eSpaulson free(ctx.out.sf_uauth); 629c1f59b3eSpaulson ctx.out.sf_uauth = NULL; 630c1f59b3eSpaulson ctx.out.sf_uauthlen = 0; 631c1f59b3eSpaulson } 632c1f59b3eSpaulson if (ctx.out.sf_pathlen > 0) { 633c1f59b3eSpaulson free(ctx.out.sf_path); 634c1f59b3eSpaulson ctx.out.sf_path = NULL; 635c1f59b3eSpaulson ctx.out.sf_pathlen = 0; 636c1f59b3eSpaulson } 637c1f59b3eSpaulson if (ctx.out.sf_atpathlen > 0) { 638c1f59b3eSpaulson free(ctx.out.sf_atpath); 639c1f59b3eSpaulson ctx.out.sf_atpath = NULL; 640c1f59b3eSpaulson ctx.out.sf_atpathlen = 0; 641c1f59b3eSpaulson } 642c1f59b3eSpaulson if (ctx.out.sf_textlen > 0) { 643c1f59b3eSpaulson free(ctx.out.sf_text); 644c1f59b3eSpaulson ctx.out.sf_text = NULL; 645c1f59b3eSpaulson ctx.out.sf_textlen = 0; 646c1f59b3eSpaulson } 647c1f59b3eSpaulson if (ctx.out.sf_zonelen > 0) { 648c1f59b3eSpaulson free(ctx.out.sf_zonename); 649c1f59b3eSpaulson ctx.out.sf_zonename = NULL; 650c1f59b3eSpaulson ctx.out.sf_zonelen = 0; 651c1f59b3eSpaulson } 652c1f59b3eSpaulson 6537c478bd9Sstevel@tonic-gate return (-1); /* tell caller it was tossed */ 6547c478bd9Sstevel@tonic-gate } 6557c478bd9Sstevel@tonic-gate bp = output; 6567c478bd9Sstevel@tonic-gate remaining = out_len; 6577c478bd9Sstevel@tonic-gate 6587c478bd9Sstevel@tonic-gate if (ctx.out.sf_eventid != 0) { 6597c478bd9Sstevel@tonic-gate au_event_ent_t *event; 6607c478bd9Sstevel@tonic-gate 6617c478bd9Sstevel@tonic-gate if (cacheauevent(&event, ctx.out.sf_eventid) < 0) 662d0fa49b7STony Nguyen used = snprintf(bp, remaining, "%hu", 6637c478bd9Sstevel@tonic-gate ctx.out.sf_eventid); 6647c478bd9Sstevel@tonic-gate else 6657c478bd9Sstevel@tonic-gate used = strlcpy(bp, event->ae_desc, remaining); 6667c478bd9Sstevel@tonic-gate bp += used; 6677c478bd9Sstevel@tonic-gate remaining -= used; 6687c478bd9Sstevel@tonic-gate } 6697c478bd9Sstevel@tonic-gate if (ctx.out.sf_pass != 0) { 6707c478bd9Sstevel@tonic-gate if (ctx.out.sf_pass < 0) 6717c478bd9Sstevel@tonic-gate used = strlcpy(bp, " failed", remaining); 6727c478bd9Sstevel@tonic-gate else 6737c478bd9Sstevel@tonic-gate used = strlcpy(bp, " ok", remaining); 6747c478bd9Sstevel@tonic-gate bp += used; 6757c478bd9Sstevel@tonic-gate remaining -= used; 6767c478bd9Sstevel@tonic-gate } 6777c478bd9Sstevel@tonic-gate if (ctx.out.sf_asid != 0) { 6787c478bd9Sstevel@tonic-gate used = snprintf(bp, remaining, " session %u", 6797c478bd9Sstevel@tonic-gate ctx.out.sf_asid); 6807c478bd9Sstevel@tonic-gate remaining -= used; 6817c478bd9Sstevel@tonic-gate bp += used; 6827c478bd9Sstevel@tonic-gate } 683f48205beScasper if (ctx.out.sf_auid != (uid_t)-2) { 6847c478bd9Sstevel@tonic-gate used = getuname(ctx.out.sf_auid, -2, bp, remaining, 6857c478bd9Sstevel@tonic-gate STRCONSTARGS(" by ")); 6867c478bd9Sstevel@tonic-gate bp += used; 6877c478bd9Sstevel@tonic-gate remaining -= used; 6887c478bd9Sstevel@tonic-gate } 689f48205beScasper if (ctx.out.sf_euid != (uid_t)-2) { 6907c478bd9Sstevel@tonic-gate /* 4 = strlen(" as ") */ 6917c478bd9Sstevel@tonic-gate used = getuname(ctx.out.sf_euid, ctx.out.sf_egid, bp, 6927c478bd9Sstevel@tonic-gate remaining, STRCONSTARGS(" as ")); 6937c478bd9Sstevel@tonic-gate bp += used; 6947c478bd9Sstevel@tonic-gate remaining -= used; 6957c478bd9Sstevel@tonic-gate } 6967c478bd9Sstevel@tonic-gate if (ctx.out.sf_zonename != NULL) { 6977c478bd9Sstevel@tonic-gate used = fromright(bp, remaining, 6987c478bd9Sstevel@tonic-gate STRCONSTARGS(" in "), 6997c478bd9Sstevel@tonic-gate ctx.out.sf_zonename, ctx.out.sf_zonelen); 7007c478bd9Sstevel@tonic-gate free(ctx.out.sf_zonename); 7017c478bd9Sstevel@tonic-gate bp += used; 7027c478bd9Sstevel@tonic-gate remaining -= used; 7037c478bd9Sstevel@tonic-gate } 7047c478bd9Sstevel@tonic-gate if (ctx.out.sf_tid.at_type != 0) { 7057c478bd9Sstevel@tonic-gate /* 6 = strlen(" from ") */ 7067c478bd9Sstevel@tonic-gate used = gethname(&(ctx.out.sf_tid), bp, remaining, 7077c478bd9Sstevel@tonic-gate STRCONSTARGS(" from ")); 7087c478bd9Sstevel@tonic-gate bp += used; 7097c478bd9Sstevel@tonic-gate remaining -= used; 7107c478bd9Sstevel@tonic-gate } 711f48205beScasper if (ctx.out.sf_pauid != (uid_t)-2) { 7127c478bd9Sstevel@tonic-gate /* 11 = strlen(" proc_auid ") */ 7137c478bd9Sstevel@tonic-gate used = getuname(ctx.out.sf_pauid, -2, bp, remaining, 7147c478bd9Sstevel@tonic-gate STRCONSTARGS(" proc_auid ")); 7157c478bd9Sstevel@tonic-gate bp += used; 7167c478bd9Sstevel@tonic-gate remaining -= used; 7177c478bd9Sstevel@tonic-gate } 718f48205beScasper if (ctx.out.sf_peuid != (uid_t)-2) { 7197c478bd9Sstevel@tonic-gate used = getuname(ctx.out.sf_peuid, -2, bp, remaining, 7207c478bd9Sstevel@tonic-gate STRCONSTARGS(" proc_uid ")); 7217c478bd9Sstevel@tonic-gate bp += used; 7227c478bd9Sstevel@tonic-gate remaining -= used; 7237c478bd9Sstevel@tonic-gate } 7247c478bd9Sstevel@tonic-gate #if DEBUG 7257c478bd9Sstevel@tonic-gate /* 7267c478bd9Sstevel@tonic-gate * with performance testing, this has the effect of 7277c478bd9Sstevel@tonic-gate * making that each message is unique, so syslogd 7287c478bd9Sstevel@tonic-gate * won't collect a series of messages as "last message 7297c478bd9Sstevel@tonic-gate * repeated n times," another reason why DEBUG 0 7307c478bd9Sstevel@tonic-gate * should perform better than DEBUG 1. However the 7317c478bd9Sstevel@tonic-gate * intention is to help debug lost data problems 7327c478bd9Sstevel@tonic-gate */ 7337c478bd9Sstevel@tonic-gate if (ctx.out.sf_sequence != -1) { 734dfc7be02SJan Friedel (void) fprintf(dbfp, 7358f775e0aSJan Friedel "syslog writing record %u / buffer %llu\n", 7367c478bd9Sstevel@tonic-gate ctx.out.sf_sequence, sequence); 7377c478bd9Sstevel@tonic-gate used = snprintf(bp, remaining, " seq %u", 7387c478bd9Sstevel@tonic-gate ctx.out.sf_sequence, sequence); 7397c478bd9Sstevel@tonic-gate remaining -= used; 7407c478bd9Sstevel@tonic-gate bp += used; 7417c478bd9Sstevel@tonic-gate } else 742dfc7be02SJan Friedel (void) fprintf(dbfp, "syslog writing buffer %llu\n", 743dfc7be02SJan Friedel sequence); 7447c478bd9Sstevel@tonic-gate #endif 7457c478bd9Sstevel@tonic-gate /* 7467c478bd9Sstevel@tonic-gate * Long fields that may need truncation go here in 7477c478bd9Sstevel@tonic-gate * order of decreasing priority. Paths are truncated 7487c478bd9Sstevel@tonic-gate * from the left, text from the right. 7497c478bd9Sstevel@tonic-gate */ 7507c478bd9Sstevel@tonic-gate if (ctx.out.sf_path != NULL) { 7517c478bd9Sstevel@tonic-gate used = fromleft(bp, remaining, STRCONSTARGS(" obj "), 7527c478bd9Sstevel@tonic-gate ctx.out.sf_path, ctx.out.sf_pathlen); 7537c478bd9Sstevel@tonic-gate free(ctx.out.sf_path); 7547c478bd9Sstevel@tonic-gate bp += used; 7557c478bd9Sstevel@tonic-gate remaining -= used; 7567c478bd9Sstevel@tonic-gate } 7577c478bd9Sstevel@tonic-gate if (ctx.out.sf_atpath != NULL) { 7587c478bd9Sstevel@tonic-gate used = fromleft(bp, remaining, 7597c478bd9Sstevel@tonic-gate STRCONSTARGS(" attr_obj "), 7607c478bd9Sstevel@tonic-gate ctx.out.sf_atpath, ctx.out.sf_atpathlen); 7617c478bd9Sstevel@tonic-gate free(ctx.out.sf_atpath); 7627c478bd9Sstevel@tonic-gate bp += used; 7637c478bd9Sstevel@tonic-gate remaining -= used; 7647c478bd9Sstevel@tonic-gate } 7657c478bd9Sstevel@tonic-gate if (ctx.out.sf_uauth != NULL) { 7667c478bd9Sstevel@tonic-gate used = fromright(bp, remaining, STRCONSTARGS(" uauth "), 7677c478bd9Sstevel@tonic-gate ctx.out.sf_uauth, ctx.out.sf_uauthlen); 7687c478bd9Sstevel@tonic-gate free(ctx.out.sf_path); 7697c478bd9Sstevel@tonic-gate bp += used; 7707c478bd9Sstevel@tonic-gate remaining -= used; 7717c478bd9Sstevel@tonic-gate } 7727c478bd9Sstevel@tonic-gate if (ctx.out.sf_text != NULL) { 7737c478bd9Sstevel@tonic-gate used = fromright(bp, remaining, 7747c478bd9Sstevel@tonic-gate STRCONSTARGS(AU_TEXT_NAME), 7757c478bd9Sstevel@tonic-gate ctx.out.sf_text, ctx.out.sf_textlen); 7767c478bd9Sstevel@tonic-gate free(ctx.out.sf_text); 7777c478bd9Sstevel@tonic-gate bp += used; 7787c478bd9Sstevel@tonic-gate remaining -= used; 7797c478bd9Sstevel@tonic-gate } 7807c478bd9Sstevel@tonic-gate } 7817c478bd9Sstevel@tonic-gate return (rc_ret); 7827c478bd9Sstevel@tonic-gate } 7837c478bd9Sstevel@tonic-gate 7847c478bd9Sstevel@tonic-gate /* 7857c478bd9Sstevel@tonic-gate * 1024 is max syslog record size, 48 is minimum header length, 7867c478bd9Sstevel@tonic-gate * assuming a hostname length of 0. maxavail reduces use of the 7877c478bd9Sstevel@tonic-gate * allocated space by the length of the hostname (see maxavail) 7887c478bd9Sstevel@tonic-gate */ 7897c478bd9Sstevel@tonic-gate #define OUTPUT_BUF_SIZE 1024 - 48 7907c478bd9Sstevel@tonic-gate 7917c478bd9Sstevel@tonic-gate /* ARGSUSED */ 7927c478bd9Sstevel@tonic-gate auditd_rc_t 7938f775e0aSJan Friedel auditd_plugin(const char *input, size_t in_len, uint64_t sequence, char **error) 7947c478bd9Sstevel@tonic-gate { 7957c478bd9Sstevel@tonic-gate char *outbuf; 7967c478bd9Sstevel@tonic-gate auditd_rc_t rc = AUDITD_SUCCESS; 7977c478bd9Sstevel@tonic-gate #if DEBUG 7988f775e0aSJan Friedel static uint64_t last_sequence = 0; 7998f775e0aSJan Friedel static uint64_t write_count = 0; 8008f775e0aSJan Friedel static uint64_t toss_count = 0; 8017c478bd9Sstevel@tonic-gate 8027c478bd9Sstevel@tonic-gate if ((last_sequence > 0) && (sequence != last_sequence + 1)) 803dfc7be02SJan Friedel (void) fprintf(dbfp, 804dfc7be02SJan Friedel "syslog: buffer sequence=%llu but prev=%llu\n", 8058f775e0aSJan Friedel sequence, last_sequence); 8067c478bd9Sstevel@tonic-gate last_sequence = sequence; 8077c478bd9Sstevel@tonic-gate #endif 8087c478bd9Sstevel@tonic-gate 8097c478bd9Sstevel@tonic-gate *error = NULL; 8107c478bd9Sstevel@tonic-gate 8117c478bd9Sstevel@tonic-gate outbuf = malloc(OUTPUT_BUF_SIZE); 8127c478bd9Sstevel@tonic-gate if (outbuf == NULL) { 8138f775e0aSJan Friedel DPRINT((dbfp, "syslog: out of memory; seq=%llu\n", 8147c478bd9Sstevel@tonic-gate sequence)); 8157c478bd9Sstevel@tonic-gate rc = AUDITD_NO_MEMORY; 8167c478bd9Sstevel@tonic-gate *error = strdup(gettext("Can't allocate buffers")); 8177c478bd9Sstevel@tonic-gate } else { 8187c478bd9Sstevel@tonic-gate rc = filter(input, sequence, outbuf, in_len, maxavail); 8197c478bd9Sstevel@tonic-gate 8207c478bd9Sstevel@tonic-gate if (rc == AUDITD_SUCCESS) { 8217c478bd9Sstevel@tonic-gate __audit_syslog("audit", LOG_NDELAY, 8227c478bd9Sstevel@tonic-gate LOG_AUDIT, LOG_NOTICE, outbuf); 8238f775e0aSJan Friedel DPRINT((dbfp, "syslog: write_count=%llu, " 8248f775e0aSJan Friedel "buffer=%llu, tossed=%llu\n", 8257c478bd9Sstevel@tonic-gate ++write_count, sequence, toss_count)); 8267c478bd9Sstevel@tonic-gate } else if (rc > 0) { /* -1 == discard it */ 8278f775e0aSJan Friedel DPRINT((dbfp, "syslog: parse failed for buffer %llu\n", 8287c478bd9Sstevel@tonic-gate sequence)); 8297c478bd9Sstevel@tonic-gate *error = strdup(gettext( 8307c478bd9Sstevel@tonic-gate "Unable to parse audit record")); 8317c478bd9Sstevel@tonic-gate } else { 8327c478bd9Sstevel@tonic-gate DPRINT((dbfp, "syslog: rc = %d (-1 is discard), " 8338f775e0aSJan Friedel "sequence=%llu, toss_count=%llu\n", 8347c478bd9Sstevel@tonic-gate rc, sequence, ++toss_count)); 8357c478bd9Sstevel@tonic-gate rc = 0; 8367c478bd9Sstevel@tonic-gate } 8377c478bd9Sstevel@tonic-gate free(outbuf); 8387c478bd9Sstevel@tonic-gate } 8397c478bd9Sstevel@tonic-gate return (rc); 8407c478bd9Sstevel@tonic-gate } 8417c478bd9Sstevel@tonic-gate 8427c478bd9Sstevel@tonic-gate auditd_rc_t 8437c478bd9Sstevel@tonic-gate auditd_plugin_open(const kva_t *kvlist, char **ret_list, char **error) 8447c478bd9Sstevel@tonic-gate { 8457c478bd9Sstevel@tonic-gate char localname[MAXHOSTNAMELEN + 1]; 8467c478bd9Sstevel@tonic-gate auditd_rc_t rc; 8477c478bd9Sstevel@tonic-gate char *value; 8487c478bd9Sstevel@tonic-gate /* kva_match doesn't do const, so copy the pointer */ 8497c478bd9Sstevel@tonic-gate kva_t *kva = (kva_t *)kvlist; 8507c478bd9Sstevel@tonic-gate 8517c478bd9Sstevel@tonic-gate *error = NULL; 8527c478bd9Sstevel@tonic-gate *ret_list = NULL; 8537c478bd9Sstevel@tonic-gate 8547c478bd9Sstevel@tonic-gate if ((kvlist == NULL) || ((value = kva_match(kva, "p_flags")) == NULL)) { 8557c478bd9Sstevel@tonic-gate *error = strdup(gettext( 8567c478bd9Sstevel@tonic-gate "The \"p_flags\" attribute is missing.")); 8577c478bd9Sstevel@tonic-gate return (AUDITD_INVALID); 8587c478bd9Sstevel@tonic-gate } 8597c478bd9Sstevel@tonic-gate if (!initialized) { 8607c478bd9Sstevel@tonic-gate #if DEBUG 8617c478bd9Sstevel@tonic-gate dbfp = __auditd_debug_file_open(); 8627c478bd9Sstevel@tonic-gate #endif 8637c478bd9Sstevel@tonic-gate initialized = 1; 8647c478bd9Sstevel@tonic-gate (void) pthread_mutex_init(&log_mutex, NULL); 8657c478bd9Sstevel@tonic-gate /* 8667c478bd9Sstevel@tonic-gate * calculate length of the local hostname for adjusting the 8677c478bd9Sstevel@tonic-gate * estimate of how much space is taken by the syslog header. 8687c478bd9Sstevel@tonic-gate * If the local hostname isn't available, leave some room 8697c478bd9Sstevel@tonic-gate * anyway. (The -2 is for the blanks on either side of the 8707c478bd9Sstevel@tonic-gate * hostname in the syslog message.) 8717c478bd9Sstevel@tonic-gate */ 8727c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&log_mutex); 8737c478bd9Sstevel@tonic-gate if (gethostname(localname, MAXHOSTNAMELEN)) 8747c478bd9Sstevel@tonic-gate maxavail = OUTPUT_BUF_SIZE - 20; 8757c478bd9Sstevel@tonic-gate else 8767c478bd9Sstevel@tonic-gate maxavail = OUTPUT_BUF_SIZE - strlen(localname) - 2; 8777c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&log_mutex); 8787c478bd9Sstevel@tonic-gate 8797c478bd9Sstevel@tonic-gate if (init_hash(hosthash, 0, HOSTHASHSIZE, MAXHOSTNAMELEN)) 8807c478bd9Sstevel@tonic-gate return (AUDITD_NO_MEMORY); 8817c478bd9Sstevel@tonic-gate 8827c478bd9Sstevel@tonic-gate if (init_hash(uidhash, -2, UIDHASHSIZE, USERNAMELEN)) 8837c478bd9Sstevel@tonic-gate return (AUDITD_NO_MEMORY); 8847c478bd9Sstevel@tonic-gate 8857c478bd9Sstevel@tonic-gate if (init_hash(gidhash, -2, GIDHASHSIZE, GIDNAMELEN)) 8867c478bd9Sstevel@tonic-gate return (AUDITD_NO_MEMORY); 8877c478bd9Sstevel@tonic-gate } 8887c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&log_mutex); 8897c478bd9Sstevel@tonic-gate if ((rc = setmask(value)) != AUDITD_SUCCESS) 8907c478bd9Sstevel@tonic-gate *error = strdup(gettext( 8917c478bd9Sstevel@tonic-gate "incorrect p_flags setting; no records will be output")); 8927c478bd9Sstevel@tonic-gate 8937c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&log_mutex); 8947c478bd9Sstevel@tonic-gate 8957c478bd9Sstevel@tonic-gate return (rc); 8967c478bd9Sstevel@tonic-gate } 8977c478bd9Sstevel@tonic-gate 8987c478bd9Sstevel@tonic-gate auditd_rc_t 8997c478bd9Sstevel@tonic-gate auditd_plugin_close(char **error) 9007c478bd9Sstevel@tonic-gate { 9017c478bd9Sstevel@tonic-gate *error = NULL; 9027c478bd9Sstevel@tonic-gate 9037c478bd9Sstevel@tonic-gate if (initialized) { 9047c478bd9Sstevel@tonic-gate (void) pthread_mutex_destroy(&log_mutex); 9057c478bd9Sstevel@tonic-gate 9067c478bd9Sstevel@tonic-gate free_hash(hosthash, HOSTHASHSIZE); 9077c478bd9Sstevel@tonic-gate free_hash(uidhash, UIDHASHSIZE); 9087c478bd9Sstevel@tonic-gate free_hash(gidhash, GIDHASHSIZE); 9097c478bd9Sstevel@tonic-gate } 9107c478bd9Sstevel@tonic-gate initialized = 0; 9117c478bd9Sstevel@tonic-gate 9127c478bd9Sstevel@tonic-gate return (AUDITD_SUCCESS); 9137c478bd9Sstevel@tonic-gate } 914