1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate * 26*7c478bd9Sstevel@tonic-gate */ 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate /* 29*7c478bd9Sstevel@tonic-gate * Threads: 30*7c478bd9Sstevel@tonic-gate * 31*7c478bd9Sstevel@tonic-gate * auditd is thread 0 and does signal handling 32*7c478bd9Sstevel@tonic-gate * 33*7c478bd9Sstevel@tonic-gate * input() is a door server that receives binary audit records and 34*7c478bd9Sstevel@tonic-gate * queues them for handling by an instance of process() for conversion to syslog 35*7c478bd9Sstevel@tonic-gate * message(s). There is one process thread per plugin. 36*7c478bd9Sstevel@tonic-gate * 37*7c478bd9Sstevel@tonic-gate * Queues: 38*7c478bd9Sstevel@tonic-gate * 39*7c478bd9Sstevel@tonic-gate * Each plugin has a buffer pool and and queue for feeding the 40*7c478bd9Sstevel@tonic-gate * the process threads. The input thread moves buffers from the pool 41*7c478bd9Sstevel@tonic-gate * to the queue and the process thread puts them back. 42*7c478bd9Sstevel@tonic-gate * 43*7c478bd9Sstevel@tonic-gate * Another pool, b_pool, contains buffers referenced by each of the 44*7c478bd9Sstevel@tonic-gate * process queues; this is to minimize the number of buffer copies 45*7c478bd9Sstevel@tonic-gate * 46*7c478bd9Sstevel@tonic-gate */ 47*7c478bd9Sstevel@tonic-gate 48*7c478bd9Sstevel@tonic-gate #include <arpa/inet.h> 49*7c478bd9Sstevel@tonic-gate #include <assert.h> 50*7c478bd9Sstevel@tonic-gate #include <bsm/adt.h> 51*7c478bd9Sstevel@tonic-gate #include <dlfcn.h> 52*7c478bd9Sstevel@tonic-gate #include <errno.h> 53*7c478bd9Sstevel@tonic-gate #include <fcntl.h> 54*7c478bd9Sstevel@tonic-gate #include <libintl.h> 55*7c478bd9Sstevel@tonic-gate #include <pthread.h> 56*7c478bd9Sstevel@tonic-gate #include <secdb.h> 57*7c478bd9Sstevel@tonic-gate #include <security/auditd.h> 58*7c478bd9Sstevel@tonic-gate #include <signal.h> 59*7c478bd9Sstevel@tonic-gate #include <stdio.h> 60*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 61*7c478bd9Sstevel@tonic-gate #include <string.h> 62*7c478bd9Sstevel@tonic-gate #include <syslog.h> 63*7c478bd9Sstevel@tonic-gate #include <sys/socket.h> 64*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 65*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 66*7c478bd9Sstevel@tonic-gate #include <unistd.h> 67*7c478bd9Sstevel@tonic-gate #include <audit_plugin.h> /* libbsm */ 68*7c478bd9Sstevel@tonic-gate #include "plugin.h" 69*7c478bd9Sstevel@tonic-gate #include <bsm/audit_door_infc.h> 70*7c478bd9Sstevel@tonic-gate #include "audit_sig_infc.h" 71*7c478bd9Sstevel@tonic-gate #include "queue.h" 72*7c478bd9Sstevel@tonic-gate 73*7c478bd9Sstevel@tonic-gate #define DEBUG 0 74*7c478bd9Sstevel@tonic-gate 75*7c478bd9Sstevel@tonic-gate #if DEBUG 76*7c478bd9Sstevel@tonic-gate 77*7c478bd9Sstevel@tonic-gate static FILE *dbfp; 78*7c478bd9Sstevel@tonic-gate #define DUMP(w, x, y, z) dump_state(w, x, y, z) 79*7c478bd9Sstevel@tonic-gate #define DPRINT(x) {(void) fprintf x; } 80*7c478bd9Sstevel@tonic-gate 81*7c478bd9Sstevel@tonic-gate #else 82*7c478bd9Sstevel@tonic-gate 83*7c478bd9Sstevel@tonic-gate #define DUMP(w, x, y, z) 84*7c478bd9Sstevel@tonic-gate #define DPRINT(x) 85*7c478bd9Sstevel@tonic-gate 86*7c478bd9Sstevel@tonic-gate #endif 87*7c478bd9Sstevel@tonic-gate 88*7c478bd9Sstevel@tonic-gate #define FATAL_MESSAGE_LEN 256 89*7c478bd9Sstevel@tonic-gate 90*7c478bd9Sstevel@tonic-gate #define MIN_RECORD_SIZE (size_t)25 91*7c478bd9Sstevel@tonic-gate 92*7c478bd9Sstevel@tonic-gate #define INPUT_MIN 2 93*7c478bd9Sstevel@tonic-gate #define THRESHOLD_PCT 75 94*7c478bd9Sstevel@tonic-gate #define DEFAULT_BUF_SZ (size_t)250 95*7c478bd9Sstevel@tonic-gate #define BASE_PRIORITY 10 /* 0 - 20 valid for user, time share */ 96*7c478bd9Sstevel@tonic-gate #define HIGH_PRIORITY BASE_PRIORITY - 1 97*7c478bd9Sstevel@tonic-gate 98*7c478bd9Sstevel@tonic-gate static thr_data_t in_thr; /* input thread locks and data */ 99*7c478bd9Sstevel@tonic-gate static int doorfd = -1; 100*7c478bd9Sstevel@tonic-gate 101*7c478bd9Sstevel@tonic-gate static int largest_queue = INPUT_MIN; 102*7c478bd9Sstevel@tonic-gate static au_queue_t b_pool; 103*7c478bd9Sstevel@tonic-gate static int b_allocated = 0; 104*7c478bd9Sstevel@tonic-gate static pthread_mutex_t b_alloc_lock; 105*7c478bd9Sstevel@tonic-gate static pthread_mutex_t b_refcnt_lock; 106*7c478bd9Sstevel@tonic-gate 107*7c478bd9Sstevel@tonic-gate static void input(void *, void *, int, door_desc_t *, int); 108*7c478bd9Sstevel@tonic-gate static void process(plugin_t *); 109*7c478bd9Sstevel@tonic-gate 110*7c478bd9Sstevel@tonic-gate static audit_q_t *qpool_withdraw(plugin_t *); 111*7c478bd9Sstevel@tonic-gate static void qpool_init(plugin_t *, int); 112*7c478bd9Sstevel@tonic-gate static void qpool_return(plugin_t *, audit_q_t *); 113*7c478bd9Sstevel@tonic-gate static void qpool_close(plugin_t *); 114*7c478bd9Sstevel@tonic-gate 115*7c478bd9Sstevel@tonic-gate static audit_rec_t *bpool_withdraw(char *, size_t, size_t); 116*7c478bd9Sstevel@tonic-gate static void bpool_init(); 117*7c478bd9Sstevel@tonic-gate static void bpool_return(audit_rec_t *); 118*7c478bd9Sstevel@tonic-gate 119*7c478bd9Sstevel@tonic-gate /* 120*7c478bd9Sstevel@tonic-gate * warn_or_fatal() -- log daemon error and (optionally) exit 121*7c478bd9Sstevel@tonic-gate */ 122*7c478bd9Sstevel@tonic-gate static void 123*7c478bd9Sstevel@tonic-gate warn_or_fatal(int fatal, char *parting_shot) 124*7c478bd9Sstevel@tonic-gate { 125*7c478bd9Sstevel@tonic-gate char *severity; 126*7c478bd9Sstevel@tonic-gate char message[512]; 127*7c478bd9Sstevel@tonic-gate 128*7c478bd9Sstevel@tonic-gate if (fatal) 129*7c478bd9Sstevel@tonic-gate severity = gettext("fatal error"); 130*7c478bd9Sstevel@tonic-gate else 131*7c478bd9Sstevel@tonic-gate severity = gettext("warning"); 132*7c478bd9Sstevel@tonic-gate 133*7c478bd9Sstevel@tonic-gate (void) snprintf(message, 512, "%s: %s", severity, parting_shot); 134*7c478bd9Sstevel@tonic-gate 135*7c478bd9Sstevel@tonic-gate __audit_syslog("auditd", LOG_PID | LOG_ODELAY | LOG_CONS, 136*7c478bd9Sstevel@tonic-gate LOG_DAEMON, LOG_ALERT, message); 137*7c478bd9Sstevel@tonic-gate 138*7c478bd9Sstevel@tonic-gate DPRINT((dbfp, "auditd warn_or_fatal %s: %s\n", severity, parting_shot)); 139*7c478bd9Sstevel@tonic-gate if (fatal) 140*7c478bd9Sstevel@tonic-gate auditd_exit(1); 141*7c478bd9Sstevel@tonic-gate } 142*7c478bd9Sstevel@tonic-gate 143*7c478bd9Sstevel@tonic-gate /* Internal to doorway.c errors... */ 144*7c478bd9Sstevel@tonic-gate #define INTERNAL_LOAD_ERROR -1 145*7c478bd9Sstevel@tonic-gate #define INTERNAL_SYS_ERROR -2 146*7c478bd9Sstevel@tonic-gate #define INTERNAL_CONFIG_ERROR -3 147*7c478bd9Sstevel@tonic-gate 148*7c478bd9Sstevel@tonic-gate /* 149*7c478bd9Sstevel@tonic-gate * report_error -- handle errors returned by plugin 150*7c478bd9Sstevel@tonic-gate * 151*7c478bd9Sstevel@tonic-gate * rc is plugin's return code if it is a non-negative value, 152*7c478bd9Sstevel@tonic-gate * otherwise it is a doorway.c code about a plugin. 153*7c478bd9Sstevel@tonic-gate */ 154*7c478bd9Sstevel@tonic-gate static void 155*7c478bd9Sstevel@tonic-gate report_error(auditd_rc_t rc, char *error_text, char *plugin_path) 156*7c478bd9Sstevel@tonic-gate { 157*7c478bd9Sstevel@tonic-gate int warn = 0; 158*7c478bd9Sstevel@tonic-gate char rcbuf[100]; /* short error name string */ 159*7c478bd9Sstevel@tonic-gate char message[FATAL_MESSAGE_LEN]; 160*7c478bd9Sstevel@tonic-gate int bad_count = 0; 161*7c478bd9Sstevel@tonic-gate char *name; 162*7c478bd9Sstevel@tonic-gate char empty[] = ".."; 163*7c478bd9Sstevel@tonic-gate 164*7c478bd9Sstevel@tonic-gate static int no_plug = 0; 165*7c478bd9Sstevel@tonic-gate static int no_load = 0; 166*7c478bd9Sstevel@tonic-gate static int no_thread; 167*7c478bd9Sstevel@tonic-gate static int no_memory = 0; 168*7c478bd9Sstevel@tonic-gate static int invalid = 0; 169*7c478bd9Sstevel@tonic-gate static int retry = 0; 170*7c478bd9Sstevel@tonic-gate static int fail = 0; 171*7c478bd9Sstevel@tonic-gate 172*7c478bd9Sstevel@tonic-gate name = plugin_path; 173*7c478bd9Sstevel@tonic-gate if (error_text == NULL) 174*7c478bd9Sstevel@tonic-gate error_text = empty; 175*7c478bd9Sstevel@tonic-gate if (name == NULL) 176*7c478bd9Sstevel@tonic-gate name = empty; 177*7c478bd9Sstevel@tonic-gate 178*7c478bd9Sstevel@tonic-gate switch (rc) { 179*7c478bd9Sstevel@tonic-gate case INTERNAL_LOAD_ERROR: 180*7c478bd9Sstevel@tonic-gate warn = 1; 181*7c478bd9Sstevel@tonic-gate bad_count = ++no_load; 182*7c478bd9Sstevel@tonic-gate (void) strcpy(rcbuf, "load_error"); 183*7c478bd9Sstevel@tonic-gate break; 184*7c478bd9Sstevel@tonic-gate case INTERNAL_SYS_ERROR: 185*7c478bd9Sstevel@tonic-gate warn = 1; 186*7c478bd9Sstevel@tonic-gate bad_count = ++no_thread; 187*7c478bd9Sstevel@tonic-gate (void) strcpy(rcbuf, "sys_error"); 188*7c478bd9Sstevel@tonic-gate break; 189*7c478bd9Sstevel@tonic-gate case INTERNAL_CONFIG_ERROR: 190*7c478bd9Sstevel@tonic-gate warn = 1; 191*7c478bd9Sstevel@tonic-gate bad_count = ++no_plug; 192*7c478bd9Sstevel@tonic-gate (void) strcpy(rcbuf, "config_error"); 193*7c478bd9Sstevel@tonic-gate name = strdup("--"); 194*7c478bd9Sstevel@tonic-gate break; 195*7c478bd9Sstevel@tonic-gate case AUDITD_SUCCESS: 196*7c478bd9Sstevel@tonic-gate break; 197*7c478bd9Sstevel@tonic-gate case AUDITD_NO_MEMORY: /* no_memory */ 198*7c478bd9Sstevel@tonic-gate warn = 1; 199*7c478bd9Sstevel@tonic-gate bad_count = ++no_memory; 200*7c478bd9Sstevel@tonic-gate (void) strcpy(rcbuf, "no_memory"); 201*7c478bd9Sstevel@tonic-gate break; 202*7c478bd9Sstevel@tonic-gate case AUDITD_INVALID: /* invalid */ 203*7c478bd9Sstevel@tonic-gate warn = 1; 204*7c478bd9Sstevel@tonic-gate bad_count = ++invalid; 205*7c478bd9Sstevel@tonic-gate (void) strcpy(rcbuf, "invalid"); 206*7c478bd9Sstevel@tonic-gate break; 207*7c478bd9Sstevel@tonic-gate case AUDITD_RETRY: 208*7c478bd9Sstevel@tonic-gate warn = 1; 209*7c478bd9Sstevel@tonic-gate bad_count = ++retry; 210*7c478bd9Sstevel@tonic-gate (void) strcpy(rcbuf, "retry"); 211*7c478bd9Sstevel@tonic-gate break; 212*7c478bd9Sstevel@tonic-gate case AUDITD_COMM_FAIL: /* comm_fail */ 213*7c478bd9Sstevel@tonic-gate (void) strcpy(rcbuf, "comm_fail"); 214*7c478bd9Sstevel@tonic-gate break; 215*7c478bd9Sstevel@tonic-gate case AUDITD_FATAL: /* failure */ 216*7c478bd9Sstevel@tonic-gate warn = 1; 217*7c478bd9Sstevel@tonic-gate bad_count = ++fail; 218*7c478bd9Sstevel@tonic-gate (void) strcpy(rcbuf, "failure"); 219*7c478bd9Sstevel@tonic-gate break; 220*7c478bd9Sstevel@tonic-gate default: 221*7c478bd9Sstevel@tonic-gate (void) strcpy(rcbuf, "error"); 222*7c478bd9Sstevel@tonic-gate break; 223*7c478bd9Sstevel@tonic-gate } 224*7c478bd9Sstevel@tonic-gate DPRINT((dbfp, "report_error(%d - %s): %s\n\t%s\n", 225*7c478bd9Sstevel@tonic-gate bad_count, name, rcbuf, error_text)); 226*7c478bd9Sstevel@tonic-gate if (warn) 227*7c478bd9Sstevel@tonic-gate __audit_dowarn2("plugin", name, rcbuf, error_text, bad_count); 228*7c478bd9Sstevel@tonic-gate else { 229*7c478bd9Sstevel@tonic-gate (void) snprintf(message, FATAL_MESSAGE_LEN, 230*7c478bd9Sstevel@tonic-gate gettext("audit plugin %s reported error = \"%s\": %s\n"), 231*7c478bd9Sstevel@tonic-gate name, rcbuf, error_text); 232*7c478bd9Sstevel@tonic-gate warn_or_fatal(0, message); 233*7c478bd9Sstevel@tonic-gate } 234*7c478bd9Sstevel@tonic-gate } 235*7c478bd9Sstevel@tonic-gate 236*7c478bd9Sstevel@tonic-gate static size_t 237*7c478bd9Sstevel@tonic-gate getlen(char *buf) 238*7c478bd9Sstevel@tonic-gate { 239*7c478bd9Sstevel@tonic-gate adr_t adr; 240*7c478bd9Sstevel@tonic-gate char tokenid; 241*7c478bd9Sstevel@tonic-gate uint32_t len; 242*7c478bd9Sstevel@tonic-gate 243*7c478bd9Sstevel@tonic-gate adr.adr_now = buf; 244*7c478bd9Sstevel@tonic-gate adr.adr_stream = buf; 245*7c478bd9Sstevel@tonic-gate 246*7c478bd9Sstevel@tonic-gate adrm_char(&adr, &tokenid, 1); 247*7c478bd9Sstevel@tonic-gate if ((tokenid == AUT_OHEADER) || (tokenid == AUT_HEADER32) || 248*7c478bd9Sstevel@tonic-gate (tokenid == AUT_HEADER32_EX) || (tokenid == AUT_HEADER64) || 249*7c478bd9Sstevel@tonic-gate (tokenid == AUT_HEADER64_EX)) { 250*7c478bd9Sstevel@tonic-gate adrm_u_int32(&adr, &len, 1); 251*7c478bd9Sstevel@tonic-gate 252*7c478bd9Sstevel@tonic-gate return (len); 253*7c478bd9Sstevel@tonic-gate } 254*7c478bd9Sstevel@tonic-gate DPRINT((dbfp, "getlen() is not looking at a header token\n")); 255*7c478bd9Sstevel@tonic-gate 256*7c478bd9Sstevel@tonic-gate return (0); 257*7c478bd9Sstevel@tonic-gate } 258*7c478bd9Sstevel@tonic-gate 259*7c478bd9Sstevel@tonic-gate /* 260*7c478bd9Sstevel@tonic-gate * load_function - call dlsym() to resolve the function address 261*7c478bd9Sstevel@tonic-gate */ 262*7c478bd9Sstevel@tonic-gate static int 263*7c478bd9Sstevel@tonic-gate load_function(plugin_t *p, char *name, auditd_rc_t (**func)()) 264*7c478bd9Sstevel@tonic-gate { 265*7c478bd9Sstevel@tonic-gate *func = (auditd_rc_t (*)())dlsym(p->plg_dlptr, name); 266*7c478bd9Sstevel@tonic-gate if (*func == NULL) { 267*7c478bd9Sstevel@tonic-gate char message[FATAL_MESSAGE_LEN]; 268*7c478bd9Sstevel@tonic-gate char *errmsg = dlerror(); 269*7c478bd9Sstevel@tonic-gate 270*7c478bd9Sstevel@tonic-gate (void) snprintf(message, FATAL_MESSAGE_LEN, 271*7c478bd9Sstevel@tonic-gate gettext("dlsym failed %s: error %s"), 272*7c478bd9Sstevel@tonic-gate name, errmsg != NULL ? errmsg : gettext("Unknown error\n")); 273*7c478bd9Sstevel@tonic-gate 274*7c478bd9Sstevel@tonic-gate warn_or_fatal(0, message); 275*7c478bd9Sstevel@tonic-gate return (-1); 276*7c478bd9Sstevel@tonic-gate } 277*7c478bd9Sstevel@tonic-gate return (0); 278*7c478bd9Sstevel@tonic-gate } 279*7c478bd9Sstevel@tonic-gate 280*7c478bd9Sstevel@tonic-gate /* 281*7c478bd9Sstevel@tonic-gate * load the auditd plug in 282*7c478bd9Sstevel@tonic-gate */ 283*7c478bd9Sstevel@tonic-gate static int 284*7c478bd9Sstevel@tonic-gate load_plugin(plugin_t *p) 285*7c478bd9Sstevel@tonic-gate { 286*7c478bd9Sstevel@tonic-gate struct stat64 stat; 287*7c478bd9Sstevel@tonic-gate int fd; 288*7c478bd9Sstevel@tonic-gate int fail = 0; 289*7c478bd9Sstevel@tonic-gate 290*7c478bd9Sstevel@tonic-gate /* 291*7c478bd9Sstevel@tonic-gate * Stat the file so we can check modes and ownerships 292*7c478bd9Sstevel@tonic-gate */ 293*7c478bd9Sstevel@tonic-gate if ((fd = open(p->plg_path, O_NONBLOCK | O_RDONLY)) != -1) { 294*7c478bd9Sstevel@tonic-gate if ((fstat64(fd, &stat) == -1) || (!S_ISREG(stat.st_mode))) 295*7c478bd9Sstevel@tonic-gate fail = 1; 296*7c478bd9Sstevel@tonic-gate } else 297*7c478bd9Sstevel@tonic-gate fail = 1; 298*7c478bd9Sstevel@tonic-gate if (fail) { 299*7c478bd9Sstevel@tonic-gate char message[FATAL_MESSAGE_LEN]; 300*7c478bd9Sstevel@tonic-gate 301*7c478bd9Sstevel@tonic-gate (void) snprintf(message, FATAL_MESSAGE_LEN, 302*7c478bd9Sstevel@tonic-gate gettext("auditd plugin: stat(%s) failed: %s\n"), 303*7c478bd9Sstevel@tonic-gate p->plg_path, strerror(errno)); 304*7c478bd9Sstevel@tonic-gate 305*7c478bd9Sstevel@tonic-gate warn_or_fatal(0, message); 306*7c478bd9Sstevel@tonic-gate return (-1); 307*7c478bd9Sstevel@tonic-gate } 308*7c478bd9Sstevel@tonic-gate /* 309*7c478bd9Sstevel@tonic-gate * Check the ownership of the file 310*7c478bd9Sstevel@tonic-gate */ 311*7c478bd9Sstevel@tonic-gate if (stat.st_uid != (uid_t)0) { 312*7c478bd9Sstevel@tonic-gate char message[FATAL_MESSAGE_LEN]; 313*7c478bd9Sstevel@tonic-gate 314*7c478bd9Sstevel@tonic-gate (void) snprintf(message, FATAL_MESSAGE_LEN, 315*7c478bd9Sstevel@tonic-gate gettext( 316*7c478bd9Sstevel@tonic-gate "auditd plugin: Owner of the module %s is not root\n"), 317*7c478bd9Sstevel@tonic-gate p->plg_path); 318*7c478bd9Sstevel@tonic-gate 319*7c478bd9Sstevel@tonic-gate warn_or_fatal(0, message); 320*7c478bd9Sstevel@tonic-gate return (-1); 321*7c478bd9Sstevel@tonic-gate } 322*7c478bd9Sstevel@tonic-gate /* 323*7c478bd9Sstevel@tonic-gate * Check the modes on the file 324*7c478bd9Sstevel@tonic-gate */ 325*7c478bd9Sstevel@tonic-gate if (stat.st_mode&S_IWGRP) { 326*7c478bd9Sstevel@tonic-gate char message[FATAL_MESSAGE_LEN]; 327*7c478bd9Sstevel@tonic-gate 328*7c478bd9Sstevel@tonic-gate (void) snprintf(message, FATAL_MESSAGE_LEN, 329*7c478bd9Sstevel@tonic-gate gettext("auditd plugin: module %s writable by group\n"), 330*7c478bd9Sstevel@tonic-gate p->plg_path); 331*7c478bd9Sstevel@tonic-gate 332*7c478bd9Sstevel@tonic-gate warn_or_fatal(0, message); 333*7c478bd9Sstevel@tonic-gate return (-1); 334*7c478bd9Sstevel@tonic-gate } 335*7c478bd9Sstevel@tonic-gate if (stat.st_mode&S_IWOTH) { 336*7c478bd9Sstevel@tonic-gate char message[FATAL_MESSAGE_LEN]; 337*7c478bd9Sstevel@tonic-gate 338*7c478bd9Sstevel@tonic-gate (void) snprintf(message, FATAL_MESSAGE_LEN, 339*7c478bd9Sstevel@tonic-gate gettext("auditd plugin: module %s writable by world\n"), 340*7c478bd9Sstevel@tonic-gate p->plg_path); 341*7c478bd9Sstevel@tonic-gate 342*7c478bd9Sstevel@tonic-gate warn_or_fatal(0, message); 343*7c478bd9Sstevel@tonic-gate return (-1); 344*7c478bd9Sstevel@tonic-gate } 345*7c478bd9Sstevel@tonic-gate /* 346*7c478bd9Sstevel@tonic-gate * Open the plugin 347*7c478bd9Sstevel@tonic-gate */ 348*7c478bd9Sstevel@tonic-gate p->plg_dlptr = dlopen(p->plg_path, RTLD_LAZY); 349*7c478bd9Sstevel@tonic-gate 350*7c478bd9Sstevel@tonic-gate if (p->plg_dlptr == NULL) { 351*7c478bd9Sstevel@tonic-gate char message[FATAL_MESSAGE_LEN]; 352*7c478bd9Sstevel@tonic-gate char *errmsg = dlerror(); 353*7c478bd9Sstevel@tonic-gate 354*7c478bd9Sstevel@tonic-gate (void) snprintf(message, FATAL_MESSAGE_LEN, 355*7c478bd9Sstevel@tonic-gate gettext("plugin load %s failed: %s\n"), 356*7c478bd9Sstevel@tonic-gate p->plg_path, errmsg != NULL ? errmsg : 357*7c478bd9Sstevel@tonic-gate gettext("Unknown error\n")); 358*7c478bd9Sstevel@tonic-gate 359*7c478bd9Sstevel@tonic-gate warn_or_fatal(0, message); 360*7c478bd9Sstevel@tonic-gate return (-1); 361*7c478bd9Sstevel@tonic-gate } 362*7c478bd9Sstevel@tonic-gate if (load_function(p, "auditd_plugin", &(p->plg_fplugin))) 363*7c478bd9Sstevel@tonic-gate return (-1); 364*7c478bd9Sstevel@tonic-gate 365*7c478bd9Sstevel@tonic-gate if (load_function(p, "auditd_plugin_open", &(p->plg_fplugin_open))) 366*7c478bd9Sstevel@tonic-gate return (-1); 367*7c478bd9Sstevel@tonic-gate 368*7c478bd9Sstevel@tonic-gate if (load_function(p, "auditd_plugin_close", &(p->plg_fplugin_close))) 369*7c478bd9Sstevel@tonic-gate return (-1); 370*7c478bd9Sstevel@tonic-gate 371*7c478bd9Sstevel@tonic-gate return (0); 372*7c478bd9Sstevel@tonic-gate } 373*7c478bd9Sstevel@tonic-gate 374*7c478bd9Sstevel@tonic-gate /* 375*7c478bd9Sstevel@tonic-gate * unload_plugin() unlinks and frees the plugin_t structure after 376*7c478bd9Sstevel@tonic-gate * freeing buffers and structures that hang off it. It also dlcloses 377*7c478bd9Sstevel@tonic-gate * the referenced plugin. The return is the next entry, which may be NULL 378*7c478bd9Sstevel@tonic-gate * 379*7c478bd9Sstevel@tonic-gate * hold plugin_mutex for this call 380*7c478bd9Sstevel@tonic-gate */ 381*7c478bd9Sstevel@tonic-gate static plugin_t * 382*7c478bd9Sstevel@tonic-gate unload_plugin(plugin_t *p) 383*7c478bd9Sstevel@tonic-gate { 384*7c478bd9Sstevel@tonic-gate plugin_t *q, **r; 385*7c478bd9Sstevel@tonic-gate 386*7c478bd9Sstevel@tonic-gate assert(pthread_mutex_trylock(&plugin_mutex) != 0); 387*7c478bd9Sstevel@tonic-gate 388*7c478bd9Sstevel@tonic-gate DPRINT((dbfp, "unload_plugin: removing %s\n", p->plg_path)); 389*7c478bd9Sstevel@tonic-gate 390*7c478bd9Sstevel@tonic-gate _kva_free(p->plg_kvlist); /* _kva_free accepts NULL */ 391*7c478bd9Sstevel@tonic-gate qpool_close(p); /* qpool_close accepts NULL pool, queue */ 392*7c478bd9Sstevel@tonic-gate DPRINT((dbfp, "unload_plugin: %s structure removed\n", p->plg_path)); 393*7c478bd9Sstevel@tonic-gate 394*7c478bd9Sstevel@tonic-gate (void) dlclose(p->plg_dlptr); 395*7c478bd9Sstevel@tonic-gate 396*7c478bd9Sstevel@tonic-gate DPRINT((dbfp, "unload_plugin: %s dlclosed\n", p->plg_path)); 397*7c478bd9Sstevel@tonic-gate free(p->plg_path); 398*7c478bd9Sstevel@tonic-gate 399*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_destroy(&(p->plg_mutex)); 400*7c478bd9Sstevel@tonic-gate (void) pthread_cond_destroy(&(p->plg_cv)); 401*7c478bd9Sstevel@tonic-gate 402*7c478bd9Sstevel@tonic-gate q = plugin_head; 403*7c478bd9Sstevel@tonic-gate r = &plugin_head; 404*7c478bd9Sstevel@tonic-gate while (q != NULL) { 405*7c478bd9Sstevel@tonic-gate if (q == p) { 406*7c478bd9Sstevel@tonic-gate *r = p->plg_next; 407*7c478bd9Sstevel@tonic-gate free(p); 408*7c478bd9Sstevel@tonic-gate break; 409*7c478bd9Sstevel@tonic-gate } 410*7c478bd9Sstevel@tonic-gate r = &(q->plg_next); 411*7c478bd9Sstevel@tonic-gate q = q->plg_next; 412*7c478bd9Sstevel@tonic-gate } 413*7c478bd9Sstevel@tonic-gate return (*r); 414*7c478bd9Sstevel@tonic-gate } 415*7c478bd9Sstevel@tonic-gate 416*7c478bd9Sstevel@tonic-gate /* 417*7c478bd9Sstevel@tonic-gate * process return values from plugin_open 418*7c478bd9Sstevel@tonic-gate * 419*7c478bd9Sstevel@tonic-gate * presently no attribute is defined. 420*7c478bd9Sstevel@tonic-gate */ 421*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 422*7c478bd9Sstevel@tonic-gate static void 423*7c478bd9Sstevel@tonic-gate open_return(plugin_t *p, char *attrval) 424*7c478bd9Sstevel@tonic-gate { 425*7c478bd9Sstevel@tonic-gate } 426*7c478bd9Sstevel@tonic-gate 427*7c478bd9Sstevel@tonic-gate /* 428*7c478bd9Sstevel@tonic-gate * auditd_thread_init 429*7c478bd9Sstevel@tonic-gate * - create threads 430*7c478bd9Sstevel@tonic-gate * - load plugins 431*7c478bd9Sstevel@tonic-gate * 432*7c478bd9Sstevel@tonic-gate * auditd_thread_init is called at auditd startup with an initial list 433*7c478bd9Sstevel@tonic-gate * of plugins and again each time audit catches a AU_SIG_READ_CONTROL 434*7c478bd9Sstevel@tonic-gate * or AU_SIG_NEXT_DIR. 435*7c478bd9Sstevel@tonic-gate * 436*7c478bd9Sstevel@tonic-gate */ 437*7c478bd9Sstevel@tonic-gate int 438*7c478bd9Sstevel@tonic-gate auditd_thread_init() 439*7c478bd9Sstevel@tonic-gate { 440*7c478bd9Sstevel@tonic-gate int threshold; 441*7c478bd9Sstevel@tonic-gate auditd_rc_t rc; 442*7c478bd9Sstevel@tonic-gate plugin_t *p; 443*7c478bd9Sstevel@tonic-gate char *open_params; 444*7c478bd9Sstevel@tonic-gate char *error_string; 445*7c478bd9Sstevel@tonic-gate int plugin_count = 0; 446*7c478bd9Sstevel@tonic-gate static int threads_ready = 0; 447*7c478bd9Sstevel@tonic-gate 448*7c478bd9Sstevel@tonic-gate if (!threads_ready) { 449*7c478bd9Sstevel@tonic-gate struct sched_param param; 450*7c478bd9Sstevel@tonic-gate #if DEBUG 451*7c478bd9Sstevel@tonic-gate dbfp = __auditd_debug_file_open(); 452*7c478bd9Sstevel@tonic-gate #endif 453*7c478bd9Sstevel@tonic-gate doorfd = door_create((void(*)())input, 0, 454*7c478bd9Sstevel@tonic-gate DOOR_REFUSE_DESC | DOOR_NO_CANCEL); 455*7c478bd9Sstevel@tonic-gate if (doorfd < 0) 456*7c478bd9Sstevel@tonic-gate return (1); /* can't create door -> fatal */ 457*7c478bd9Sstevel@tonic-gate 458*7c478bd9Sstevel@tonic-gate param.sched_priority = BASE_PRIORITY; 459*7c478bd9Sstevel@tonic-gate (void) pthread_setschedparam(pthread_self(), SCHED_OTHER, 460*7c478bd9Sstevel@tonic-gate ¶m); 461*7c478bd9Sstevel@tonic-gate 462*7c478bd9Sstevel@tonic-gate /* input door server */ 463*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_init(&(in_thr.thd_mutex), NULL); 464*7c478bd9Sstevel@tonic-gate (void) pthread_cond_init(&(in_thr.thd_cv), NULL); 465*7c478bd9Sstevel@tonic-gate in_thr.thd_waiting = 0; 466*7c478bd9Sstevel@tonic-gate 467*7c478bd9Sstevel@tonic-gate bpool_init(); 468*7c478bd9Sstevel@tonic-gate } 469*7c478bd9Sstevel@tonic-gate p = plugin_head; 470*7c478bd9Sstevel@tonic-gate while (p != NULL) { 471*7c478bd9Sstevel@tonic-gate if (p->plg_removed) { 472*7c478bd9Sstevel@tonic-gate DPRINT((dbfp, "start removing %s\n", p->plg_path)); 473*7c478bd9Sstevel@tonic-gate /* tell process(p) to exit and dlclose */ 474*7c478bd9Sstevel@tonic-gate (void) pthread_cond_signal(&(p->plg_cv)); 475*7c478bd9Sstevel@tonic-gate } else if (!p->plg_initialized) { 476*7c478bd9Sstevel@tonic-gate DPRINT((dbfp, "start initial load of %s\n", 477*7c478bd9Sstevel@tonic-gate p->plg_path)); 478*7c478bd9Sstevel@tonic-gate if (load_plugin(p)) { 479*7c478bd9Sstevel@tonic-gate report_error(INTERNAL_LOAD_ERROR, 480*7c478bd9Sstevel@tonic-gate gettext("dynamic load failed"), 481*7c478bd9Sstevel@tonic-gate p->plg_path); 482*7c478bd9Sstevel@tonic-gate p = unload_plugin(p); 483*7c478bd9Sstevel@tonic-gate continue; 484*7c478bd9Sstevel@tonic-gate } 485*7c478bd9Sstevel@tonic-gate open_params = NULL; 486*7c478bd9Sstevel@tonic-gate error_string = NULL; 487*7c478bd9Sstevel@tonic-gate if ((rc = p->plg_fplugin_open( 488*7c478bd9Sstevel@tonic-gate p->plg_kvlist, 489*7c478bd9Sstevel@tonic-gate &open_params, &error_string)) != AUDITD_SUCCESS) { 490*7c478bd9Sstevel@tonic-gate report_error(rc, error_string, p->plg_path); 491*7c478bd9Sstevel@tonic-gate free(error_string); 492*7c478bd9Sstevel@tonic-gate p = unload_plugin(p); 493*7c478bd9Sstevel@tonic-gate continue; 494*7c478bd9Sstevel@tonic-gate } 495*7c478bd9Sstevel@tonic-gate open_return(p, open_params); 496*7c478bd9Sstevel@tonic-gate p->plg_reopen = 0; 497*7c478bd9Sstevel@tonic-gate 498*7c478bd9Sstevel@tonic-gate threshold = ((p->plg_qmax * THRESHOLD_PCT) + 99) / 100; 499*7c478bd9Sstevel@tonic-gate p->plg_qmin = INPUT_MIN; 500*7c478bd9Sstevel@tonic-gate 501*7c478bd9Sstevel@tonic-gate DPRINT((dbfp, 502*7c478bd9Sstevel@tonic-gate "calling qpool_init for %s with qmax=%d\n", 503*7c478bd9Sstevel@tonic-gate p->plg_path, p->plg_qmax)); 504*7c478bd9Sstevel@tonic-gate 505*7c478bd9Sstevel@tonic-gate qpool_init(p, threshold); 506*7c478bd9Sstevel@tonic-gate audit_queue_init(&(p->plg_queue)); 507*7c478bd9Sstevel@tonic-gate p->plg_initialized = 1; 508*7c478bd9Sstevel@tonic-gate 509*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_init(&(p->plg_mutex), NULL); 510*7c478bd9Sstevel@tonic-gate (void) pthread_cond_init(&(p->plg_cv), NULL); 511*7c478bd9Sstevel@tonic-gate p->plg_waiting = 0; 512*7c478bd9Sstevel@tonic-gate 513*7c478bd9Sstevel@tonic-gate if (pthread_create(&(p->plg_tid), NULL, 514*7c478bd9Sstevel@tonic-gate (void *(*)(void *))process, p)) { 515*7c478bd9Sstevel@tonic-gate report_error(INTERNAL_SYS_ERROR, 516*7c478bd9Sstevel@tonic-gate gettext("thread creation failed"), 517*7c478bd9Sstevel@tonic-gate p->plg_path); 518*7c478bd9Sstevel@tonic-gate p = unload_plugin(p); 519*7c478bd9Sstevel@tonic-gate continue; 520*7c478bd9Sstevel@tonic-gate } 521*7c478bd9Sstevel@tonic-gate } else if (p->plg_reopen) { 522*7c478bd9Sstevel@tonic-gate DPRINT((dbfp, "reopen %s\n", p->plg_path)); 523*7c478bd9Sstevel@tonic-gate error_string = NULL; 524*7c478bd9Sstevel@tonic-gate if ((rc = p->plg_fplugin_open( 525*7c478bd9Sstevel@tonic-gate p->plg_kvlist, 526*7c478bd9Sstevel@tonic-gate &open_params, &error_string)) != AUDITD_SUCCESS) { 527*7c478bd9Sstevel@tonic-gate 528*7c478bd9Sstevel@tonic-gate report_error(rc, error_string, p->plg_path); 529*7c478bd9Sstevel@tonic-gate free(error_string); 530*7c478bd9Sstevel@tonic-gate p = unload_plugin(p); 531*7c478bd9Sstevel@tonic-gate continue; 532*7c478bd9Sstevel@tonic-gate } 533*7c478bd9Sstevel@tonic-gate open_return(p, open_params); 534*7c478bd9Sstevel@tonic-gate p->plg_reopen = 0; 535*7c478bd9Sstevel@tonic-gate 536*7c478bd9Sstevel@tonic-gate DPRINT((dbfp, "%s qmax=%d\n", 537*7c478bd9Sstevel@tonic-gate p->plg_path, p->plg_qmax)); 538*7c478bd9Sstevel@tonic-gate 539*7c478bd9Sstevel@tonic-gate } 540*7c478bd9Sstevel@tonic-gate p->plg_q_threshold = ((p->plg_qmax * THRESHOLD_PCT) + 99) / 100; 541*7c478bd9Sstevel@tonic-gate 542*7c478bd9Sstevel@tonic-gate p = p->plg_next; 543*7c478bd9Sstevel@tonic-gate plugin_count++; 544*7c478bd9Sstevel@tonic-gate } 545*7c478bd9Sstevel@tonic-gate if (plugin_count == 0) { 546*7c478bd9Sstevel@tonic-gate report_error(INTERNAL_CONFIG_ERROR, 547*7c478bd9Sstevel@tonic-gate gettext("No plugins are configured"), NULL); 548*7c478bd9Sstevel@tonic-gate return (-1); 549*7c478bd9Sstevel@tonic-gate } 550*7c478bd9Sstevel@tonic-gate if (!threads_ready) { 551*7c478bd9Sstevel@tonic-gate /* unleash the kernel */ 552*7c478bd9Sstevel@tonic-gate rc = auditdoor(doorfd); 553*7c478bd9Sstevel@tonic-gate 554*7c478bd9Sstevel@tonic-gate DPRINT((dbfp, "%d returned from auditdoor.\n", 555*7c478bd9Sstevel@tonic-gate rc)); 556*7c478bd9Sstevel@tonic-gate if (rc != 0) 557*7c478bd9Sstevel@tonic-gate return (1); /* fatal */ 558*7c478bd9Sstevel@tonic-gate 559*7c478bd9Sstevel@tonic-gate threads_ready = 1; 560*7c478bd9Sstevel@tonic-gate } 561*7c478bd9Sstevel@tonic-gate return (0); 562*7c478bd9Sstevel@tonic-gate } 563*7c478bd9Sstevel@tonic-gate 564*7c478bd9Sstevel@tonic-gate /* 565*7c478bd9Sstevel@tonic-gate * Door invocations that are in progress during a 566*7c478bd9Sstevel@tonic-gate * door_revoke() invocation are allowed to complete normally. 567*7c478bd9Sstevel@tonic-gate * -- man page for door_revoke() 568*7c478bd9Sstevel@tonic-gate */ 569*7c478bd9Sstevel@tonic-gate void 570*7c478bd9Sstevel@tonic-gate auditd_thread_close() 571*7c478bd9Sstevel@tonic-gate { 572*7c478bd9Sstevel@tonic-gate if (doorfd == -1) 573*7c478bd9Sstevel@tonic-gate return; 574*7c478bd9Sstevel@tonic-gate (void) door_revoke(doorfd); 575*7c478bd9Sstevel@tonic-gate doorfd = -1; 576*7c478bd9Sstevel@tonic-gate } 577*7c478bd9Sstevel@tonic-gate 578*7c478bd9Sstevel@tonic-gate /* 579*7c478bd9Sstevel@tonic-gate * qpool_init() sets up pool for queue entries (audit_q_t) 580*7c478bd9Sstevel@tonic-gate * 581*7c478bd9Sstevel@tonic-gate */ 582*7c478bd9Sstevel@tonic-gate static void 583*7c478bd9Sstevel@tonic-gate qpool_init(plugin_t *p, int threshold) 584*7c478bd9Sstevel@tonic-gate { 585*7c478bd9Sstevel@tonic-gate int i; 586*7c478bd9Sstevel@tonic-gate audit_q_t *node; 587*7c478bd9Sstevel@tonic-gate 588*7c478bd9Sstevel@tonic-gate audit_queue_init(&(p->plg_pool)); 589*7c478bd9Sstevel@tonic-gate 590*7c478bd9Sstevel@tonic-gate DPRINT((dbfp, "qpool_init(%d) max, min, threshhold = %d, %d, %d\n", 591*7c478bd9Sstevel@tonic-gate p->plg_tid, p->plg_qmax, p->plg_qmin, threshold)); 592*7c478bd9Sstevel@tonic-gate 593*7c478bd9Sstevel@tonic-gate if (p->plg_qmax > largest_queue) 594*7c478bd9Sstevel@tonic-gate largest_queue = p->plg_qmax; 595*7c478bd9Sstevel@tonic-gate 596*7c478bd9Sstevel@tonic-gate p->plg_q_threshold = threshold; 597*7c478bd9Sstevel@tonic-gate 598*7c478bd9Sstevel@tonic-gate for (i = 0; i < p->plg_qmin; i++) { 599*7c478bd9Sstevel@tonic-gate node = malloc(sizeof (audit_q_t)); 600*7c478bd9Sstevel@tonic-gate if (node == NULL) 601*7c478bd9Sstevel@tonic-gate warn_or_fatal(1, gettext("no memory\n")); 602*7c478bd9Sstevel@tonic-gate /* doesn't return */ 603*7c478bd9Sstevel@tonic-gate 604*7c478bd9Sstevel@tonic-gate audit_enqueue(&p->plg_pool, node); 605*7c478bd9Sstevel@tonic-gate } 606*7c478bd9Sstevel@tonic-gate } 607*7c478bd9Sstevel@tonic-gate 608*7c478bd9Sstevel@tonic-gate /* 609*7c478bd9Sstevel@tonic-gate * bpool_init() sets up pool and queue for record entries (audit_rec_t) 610*7c478bd9Sstevel@tonic-gate * 611*7c478bd9Sstevel@tonic-gate */ 612*7c478bd9Sstevel@tonic-gate static void 613*7c478bd9Sstevel@tonic-gate bpool_init() 614*7c478bd9Sstevel@tonic-gate { 615*7c478bd9Sstevel@tonic-gate int i; 616*7c478bd9Sstevel@tonic-gate audit_rec_t *node; 617*7c478bd9Sstevel@tonic-gate 618*7c478bd9Sstevel@tonic-gate audit_queue_init(&b_pool); 619*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_init(&b_alloc_lock, NULL); 620*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_init(&b_refcnt_lock, NULL); 621*7c478bd9Sstevel@tonic-gate 622*7c478bd9Sstevel@tonic-gate for (i = 0; i < INPUT_MIN; i++) { 623*7c478bd9Sstevel@tonic-gate node = malloc(AUDIT_REC_HEADER + DEFAULT_BUF_SZ); 624*7c478bd9Sstevel@tonic-gate if (node == NULL) 625*7c478bd9Sstevel@tonic-gate warn_or_fatal(1, gettext("no memory\n")); 626*7c478bd9Sstevel@tonic-gate /* doesn't return */ 627*7c478bd9Sstevel@tonic-gate 628*7c478bd9Sstevel@tonic-gate node->abq_buf_len = DEFAULT_BUF_SZ; 629*7c478bd9Sstevel@tonic-gate 630*7c478bd9Sstevel@tonic-gate node->abq_data_len = 0; 631*7c478bd9Sstevel@tonic-gate audit_enqueue(&b_pool, node); 632*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&b_alloc_lock); 633*7c478bd9Sstevel@tonic-gate b_allocated++; 634*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&b_alloc_lock); 635*7c478bd9Sstevel@tonic-gate } 636*7c478bd9Sstevel@tonic-gate } 637*7c478bd9Sstevel@tonic-gate 638*7c478bd9Sstevel@tonic-gate /* 639*7c478bd9Sstevel@tonic-gate * qpool_close() discard queue and pool for a discontinued plugin 640*7c478bd9Sstevel@tonic-gate * 641*7c478bd9Sstevel@tonic-gate * there is no corresponding bpool_close() since it would only 642*7c478bd9Sstevel@tonic-gate * be called as auditd is going down. 643*7c478bd9Sstevel@tonic-gate */ 644*7c478bd9Sstevel@tonic-gate static void 645*7c478bd9Sstevel@tonic-gate qpool_close(plugin_t *p) { 646*7c478bd9Sstevel@tonic-gate audit_q_t *q_node; 647*7c478bd9Sstevel@tonic-gate audit_rec_t *b_node; 648*7c478bd9Sstevel@tonic-gate 649*7c478bd9Sstevel@tonic-gate if (!p->plg_initialized) 650*7c478bd9Sstevel@tonic-gate return; 651*7c478bd9Sstevel@tonic-gate 652*7c478bd9Sstevel@tonic-gate while (audit_dequeue(&(p->plg_pool), (void *)&q_node) == 0) { 653*7c478bd9Sstevel@tonic-gate free(q_node); 654*7c478bd9Sstevel@tonic-gate } 655*7c478bd9Sstevel@tonic-gate audit_queue_destroy(&(p->plg_pool)); 656*7c478bd9Sstevel@tonic-gate 657*7c478bd9Sstevel@tonic-gate while (audit_dequeue(&(p->plg_queue), (void *)&q_node) == 0) { 658*7c478bd9Sstevel@tonic-gate b_node = audit_release(&b_refcnt_lock, q_node->aqq_data); 659*7c478bd9Sstevel@tonic-gate if (b_node != NULL) 660*7c478bd9Sstevel@tonic-gate audit_enqueue(&b_pool, b_node); 661*7c478bd9Sstevel@tonic-gate free(q_node); 662*7c478bd9Sstevel@tonic-gate } 663*7c478bd9Sstevel@tonic-gate audit_queue_destroy(&(p->plg_queue)); 664*7c478bd9Sstevel@tonic-gate } 665*7c478bd9Sstevel@tonic-gate 666*7c478bd9Sstevel@tonic-gate /* 667*7c478bd9Sstevel@tonic-gate * qpool_withdraw 668*7c478bd9Sstevel@tonic-gate */ 669*7c478bd9Sstevel@tonic-gate static audit_q_t * 670*7c478bd9Sstevel@tonic-gate qpool_withdraw(plugin_t *p) 671*7c478bd9Sstevel@tonic-gate { 672*7c478bd9Sstevel@tonic-gate audit_q_t *node; 673*7c478bd9Sstevel@tonic-gate int rc; 674*7c478bd9Sstevel@tonic-gate 675*7c478bd9Sstevel@tonic-gate /* get a buffer from the pool, if any */ 676*7c478bd9Sstevel@tonic-gate rc = audit_dequeue(&(p->plg_pool), (void *)&node); 677*7c478bd9Sstevel@tonic-gate if (rc == 0) 678*7c478bd9Sstevel@tonic-gate return (node); 679*7c478bd9Sstevel@tonic-gate 680*7c478bd9Sstevel@tonic-gate /* 681*7c478bd9Sstevel@tonic-gate * the pool is empty: allocate a new element 682*7c478bd9Sstevel@tonic-gate */ 683*7c478bd9Sstevel@tonic-gate node = malloc(sizeof (audit_q_t)); 684*7c478bd9Sstevel@tonic-gate 685*7c478bd9Sstevel@tonic-gate if (node == NULL) 686*7c478bd9Sstevel@tonic-gate warn_or_fatal(1, gettext("no memory\n")); 687*7c478bd9Sstevel@tonic-gate /* doesn't return */ 688*7c478bd9Sstevel@tonic-gate 689*7c478bd9Sstevel@tonic-gate return (node); 690*7c478bd9Sstevel@tonic-gate } 691*7c478bd9Sstevel@tonic-gate 692*7c478bd9Sstevel@tonic-gate /* 693*7c478bd9Sstevel@tonic-gate * bpool_withdraw -- gets a buffer and fills it 694*7c478bd9Sstevel@tonic-gate * 695*7c478bd9Sstevel@tonic-gate */ 696*7c478bd9Sstevel@tonic-gate static audit_rec_t * 697*7c478bd9Sstevel@tonic-gate bpool_withdraw(char *buffer, size_t buff_size, size_t request_size) 698*7c478bd9Sstevel@tonic-gate { 699*7c478bd9Sstevel@tonic-gate audit_rec_t *node; 700*7c478bd9Sstevel@tonic-gate int rc; 701*7c478bd9Sstevel@tonic-gate size_t new_length; 702*7c478bd9Sstevel@tonic-gate 703*7c478bd9Sstevel@tonic-gate new_length = (request_size > DEFAULT_BUF_SZ) ? 704*7c478bd9Sstevel@tonic-gate request_size : DEFAULT_BUF_SZ; 705*7c478bd9Sstevel@tonic-gate 706*7c478bd9Sstevel@tonic-gate /* get a buffer from the pool, if any */ 707*7c478bd9Sstevel@tonic-gate rc = audit_dequeue(&b_pool, (void *)&node); 708*7c478bd9Sstevel@tonic-gate 709*7c478bd9Sstevel@tonic-gate DPRINT((dbfp, "bpool_withdraw buf length=%d," 710*7c478bd9Sstevel@tonic-gate " requested size=%d, dequeue rc=%d\n", 711*7c478bd9Sstevel@tonic-gate new_length, request_size, rc)); 712*7c478bd9Sstevel@tonic-gate 713*7c478bd9Sstevel@tonic-gate if (rc == 0) { 714*7c478bd9Sstevel@tonic-gate DPRINT((dbfp, "bpool_withdraw node=%X (pool=%d)\n", node, 715*7c478bd9Sstevel@tonic-gate audit_queue_size(&b_pool))); 716*7c478bd9Sstevel@tonic-gate 717*7c478bd9Sstevel@tonic-gate if (new_length > node->abq_buf_len) { 718*7c478bd9Sstevel@tonic-gate node = realloc(node, AUDIT_REC_HEADER + new_length); 719*7c478bd9Sstevel@tonic-gate if (node == NULL) 720*7c478bd9Sstevel@tonic-gate warn_or_fatal(1, gettext("no memory\n")); 721*7c478bd9Sstevel@tonic-gate /* no return */ 722*7c478bd9Sstevel@tonic-gate } 723*7c478bd9Sstevel@tonic-gate } else { 724*7c478bd9Sstevel@tonic-gate /* 725*7c478bd9Sstevel@tonic-gate * the pool is empty: allocate a new element 726*7c478bd9Sstevel@tonic-gate */ 727*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&b_alloc_lock); 728*7c478bd9Sstevel@tonic-gate if (b_allocated >= largest_queue) { 729*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&b_alloc_lock); 730*7c478bd9Sstevel@tonic-gate DPRINT((dbfp, "bpool_withdraw is over max (pool=%d)\n", 731*7c478bd9Sstevel@tonic-gate audit_queue_size(&b_pool))); 732*7c478bd9Sstevel@tonic-gate return (NULL); 733*7c478bd9Sstevel@tonic-gate } 734*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&b_alloc_lock); 735*7c478bd9Sstevel@tonic-gate 736*7c478bd9Sstevel@tonic-gate node = malloc(AUDIT_REC_HEADER + new_length); 737*7c478bd9Sstevel@tonic-gate 738*7c478bd9Sstevel@tonic-gate if (node == NULL) 739*7c478bd9Sstevel@tonic-gate warn_or_fatal(1, gettext("no memory\n")); 740*7c478bd9Sstevel@tonic-gate /* no return */ 741*7c478bd9Sstevel@tonic-gate 742*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&b_alloc_lock); 743*7c478bd9Sstevel@tonic-gate b_allocated++; 744*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&b_alloc_lock); 745*7c478bd9Sstevel@tonic-gate DPRINT((dbfp, "bpool_withdraw node=%X (alloc=%d, pool=%d)\n", 746*7c478bd9Sstevel@tonic-gate node, b_allocated, audit_queue_size(&b_pool))); 747*7c478bd9Sstevel@tonic-gate } 748*7c478bd9Sstevel@tonic-gate assert(request_size <= new_length); 749*7c478bd9Sstevel@tonic-gate 750*7c478bd9Sstevel@tonic-gate (void) memcpy(node->abq_buffer, buffer, buff_size); 751*7c478bd9Sstevel@tonic-gate node->abq_data_len = buff_size; 752*7c478bd9Sstevel@tonic-gate node->abq_buf_len = new_length; 753*7c478bd9Sstevel@tonic-gate node->abq_ref_count = 0; 754*7c478bd9Sstevel@tonic-gate 755*7c478bd9Sstevel@tonic-gate return (node); 756*7c478bd9Sstevel@tonic-gate } 757*7c478bd9Sstevel@tonic-gate 758*7c478bd9Sstevel@tonic-gate /* 759*7c478bd9Sstevel@tonic-gate * qpool_return() moves queue nodes back to the pool queue. 760*7c478bd9Sstevel@tonic-gate * 761*7c478bd9Sstevel@tonic-gate * if the pool is over max, the node is discarded instead. 762*7c478bd9Sstevel@tonic-gate */ 763*7c478bd9Sstevel@tonic-gate static void 764*7c478bd9Sstevel@tonic-gate qpool_return(plugin_t *p, audit_q_t *node) 765*7c478bd9Sstevel@tonic-gate { 766*7c478bd9Sstevel@tonic-gate int qpool_size; 767*7c478bd9Sstevel@tonic-gate int q_size; 768*7c478bd9Sstevel@tonic-gate 769*7c478bd9Sstevel@tonic-gate #if DEBUG 770*7c478bd9Sstevel@tonic-gate uint32_t sequence = node->aqq_sequence; 771*7c478bd9Sstevel@tonic-gate #endif 772*7c478bd9Sstevel@tonic-gate qpool_size = audit_queue_size(&(p->plg_pool)); 773*7c478bd9Sstevel@tonic-gate q_size = audit_queue_size(&(p->plg_queue)); 774*7c478bd9Sstevel@tonic-gate 775*7c478bd9Sstevel@tonic-gate if (qpool_size + q_size > p->plg_qmax) 776*7c478bd9Sstevel@tonic-gate free(node); 777*7c478bd9Sstevel@tonic-gate else 778*7c478bd9Sstevel@tonic-gate audit_enqueue(&(p->plg_pool), node); 779*7c478bd9Sstevel@tonic-gate 780*7c478bd9Sstevel@tonic-gate DPRINT((dbfp, 781*7c478bd9Sstevel@tonic-gate "qpool_return(%d): seq=%d, q size=%d," 782*7c478bd9Sstevel@tonic-gate " pool size=%d (total alloc=%d), threshhold=%d\n", 783*7c478bd9Sstevel@tonic-gate p->plg_tid, sequence, q_size, qpool_size, 784*7c478bd9Sstevel@tonic-gate q_size + qpool_size, p->plg_q_threshold)); 785*7c478bd9Sstevel@tonic-gate } 786*7c478bd9Sstevel@tonic-gate 787*7c478bd9Sstevel@tonic-gate /* 788*7c478bd9Sstevel@tonic-gate * bpool_return() moves queue nodes back to the pool queue. 789*7c478bd9Sstevel@tonic-gate */ 790*7c478bd9Sstevel@tonic-gate static void 791*7c478bd9Sstevel@tonic-gate bpool_return(audit_rec_t *node) 792*7c478bd9Sstevel@tonic-gate { 793*7c478bd9Sstevel@tonic-gate #if DEBUG 794*7c478bd9Sstevel@tonic-gate audit_rec_t *copy = node; 795*7c478bd9Sstevel@tonic-gate #endif 796*7c478bd9Sstevel@tonic-gate node = audit_release(&b_refcnt_lock, node); /* decrement ref cnt */ 797*7c478bd9Sstevel@tonic-gate 798*7c478bd9Sstevel@tonic-gate if (node != NULL) { /* NULL if ref cnt is not zero */ 799*7c478bd9Sstevel@tonic-gate audit_enqueue(&b_pool, node); 800*7c478bd9Sstevel@tonic-gate DPRINT((dbfp, 801*7c478bd9Sstevel@tonic-gate "bpool_return: requeue %X (allocated=%d," 802*7c478bd9Sstevel@tonic-gate " pool size=%d)\n", node, b_allocated, 803*7c478bd9Sstevel@tonic-gate audit_queue_size(&b_pool))); 804*7c478bd9Sstevel@tonic-gate } 805*7c478bd9Sstevel@tonic-gate #if DEBUG 806*7c478bd9Sstevel@tonic-gate else { 807*7c478bd9Sstevel@tonic-gate DPRINT((dbfp, 808*7c478bd9Sstevel@tonic-gate "bpool_return: decrement count for %X (allocated=%d," 809*7c478bd9Sstevel@tonic-gate " pool size=%d)\n", copy, b_allocated, 810*7c478bd9Sstevel@tonic-gate audit_queue_size(&b_pool))); 811*7c478bd9Sstevel@tonic-gate } 812*7c478bd9Sstevel@tonic-gate #endif 813*7c478bd9Sstevel@tonic-gate } 814*7c478bd9Sstevel@tonic-gate 815*7c478bd9Sstevel@tonic-gate #if DEBUG 816*7c478bd9Sstevel@tonic-gate static void 817*7c478bd9Sstevel@tonic-gate dump_state(char *src, plugin_t *p, int count, char *msg) 818*7c478bd9Sstevel@tonic-gate { 819*7c478bd9Sstevel@tonic-gate struct sched_param param; 820*7c478bd9Sstevel@tonic-gate int policy; 821*7c478bd9Sstevel@tonic-gate /* 822*7c478bd9Sstevel@tonic-gate * count is message sequence 823*7c478bd9Sstevel@tonic-gate */ 824*7c478bd9Sstevel@tonic-gate (void) pthread_getschedparam(p->plg_tid, &policy, ¶m); 825*7c478bd9Sstevel@tonic-gate (void) fprintf(dbfp, "%7s(%d/%d) %11s:" 826*7c478bd9Sstevel@tonic-gate " input_in_wait=%d" 827*7c478bd9Sstevel@tonic-gate " priority=%d" 828*7c478bd9Sstevel@tonic-gate " queue size=%d pool size=%d" 829*7c478bd9Sstevel@tonic-gate "\n\t" 830*7c478bd9Sstevel@tonic-gate "process wait=%d" 831*7c478bd9Sstevel@tonic-gate " tossed=%d" 832*7c478bd9Sstevel@tonic-gate " queued=%d" 833*7c478bd9Sstevel@tonic-gate " written=%d" 834*7c478bd9Sstevel@tonic-gate "\n", 835*7c478bd9Sstevel@tonic-gate src, p->plg_tid, count, msg, 836*7c478bd9Sstevel@tonic-gate in_thr.thd_waiting, param.sched_priority, 837*7c478bd9Sstevel@tonic-gate audit_queue_size(&(p->plg_queue)), 838*7c478bd9Sstevel@tonic-gate audit_queue_size(&(p->plg_pool)), 839*7c478bd9Sstevel@tonic-gate p->plg_waiting, p->plg_tossed, 840*7c478bd9Sstevel@tonic-gate p->plg_queued, p->plg_output); 841*7c478bd9Sstevel@tonic-gate 842*7c478bd9Sstevel@tonic-gate (void) fflush(dbfp); 843*7c478bd9Sstevel@tonic-gate } 844*7c478bd9Sstevel@tonic-gate #endif 845*7c478bd9Sstevel@tonic-gate 846*7c478bd9Sstevel@tonic-gate /* 847*7c478bd9Sstevel@tonic-gate * policy_is_block: return 1 if the continue policy is off for any active 848*7c478bd9Sstevel@tonic-gate * plugin, else 0 849*7c478bd9Sstevel@tonic-gate */ 850*7c478bd9Sstevel@tonic-gate static int 851*7c478bd9Sstevel@tonic-gate policy_is_block() 852*7c478bd9Sstevel@tonic-gate { 853*7c478bd9Sstevel@tonic-gate plugin_t *p; 854*7c478bd9Sstevel@tonic-gate 855*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&plugin_mutex); 856*7c478bd9Sstevel@tonic-gate p = plugin_head; 857*7c478bd9Sstevel@tonic-gate 858*7c478bd9Sstevel@tonic-gate while (p != NULL) { 859*7c478bd9Sstevel@tonic-gate if (p->plg_cnt == 0) { 860*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&plugin_mutex); 861*7c478bd9Sstevel@tonic-gate DPRINT((dbfp, 862*7c478bd9Sstevel@tonic-gate "policy_is_block: policy is to block\n")); 863*7c478bd9Sstevel@tonic-gate return (1); 864*7c478bd9Sstevel@tonic-gate } 865*7c478bd9Sstevel@tonic-gate p = p->plg_next; 866*7c478bd9Sstevel@tonic-gate } 867*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&plugin_mutex); 868*7c478bd9Sstevel@tonic-gate DPRINT((dbfp, "policy_is_block: policy is to continue\n")); 869*7c478bd9Sstevel@tonic-gate return (0); 870*7c478bd9Sstevel@tonic-gate } 871*7c478bd9Sstevel@tonic-gate 872*7c478bd9Sstevel@tonic-gate /* 873*7c478bd9Sstevel@tonic-gate * policy_update() -- the kernel has received a policy change. 874*7c478bd9Sstevel@tonic-gate * Presently, the only policy auditd cares about is AUDIT_CNT 875*7c478bd9Sstevel@tonic-gate */ 876*7c478bd9Sstevel@tonic-gate static void 877*7c478bd9Sstevel@tonic-gate policy_update(uint32_t newpolicy) 878*7c478bd9Sstevel@tonic-gate { 879*7c478bd9Sstevel@tonic-gate plugin_t *p; 880*7c478bd9Sstevel@tonic-gate 881*7c478bd9Sstevel@tonic-gate DPRINT((dbfp, "policy change: %X\n", newpolicy)); 882*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&plugin_mutex); 883*7c478bd9Sstevel@tonic-gate p = plugin_head; 884*7c478bd9Sstevel@tonic-gate while (p != NULL) { 885*7c478bd9Sstevel@tonic-gate p->plg_cnt = (newpolicy & AUDIT_CNT) ? 1 : 0; 886*7c478bd9Sstevel@tonic-gate (void) pthread_cond_signal(&(p->plg_cv)); 887*7c478bd9Sstevel@tonic-gate 888*7c478bd9Sstevel@tonic-gate DPRINT((dbfp, "policy changed for thread %d\n", p->plg_tid)); 889*7c478bd9Sstevel@tonic-gate p = p->plg_next; 890*7c478bd9Sstevel@tonic-gate } 891*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&plugin_mutex); 892*7c478bd9Sstevel@tonic-gate } 893*7c478bd9Sstevel@tonic-gate 894*7c478bd9Sstevel@tonic-gate /* 895*7c478bd9Sstevel@tonic-gate * queue_buffer() inputs a buffer and queues for each active plugin if 896*7c478bd9Sstevel@tonic-gate * it represents a complete audit record. Otherwise it builds a 897*7c478bd9Sstevel@tonic-gate * larger buffer to hold the record and take successive buffers from 898*7c478bd9Sstevel@tonic-gate * c2audit to build a complete record; then queues it for each plugin. 899*7c478bd9Sstevel@tonic-gate * 900*7c478bd9Sstevel@tonic-gate * return 0 if data is queued (or damaged and tossed). If resources 901*7c478bd9Sstevel@tonic-gate * are not available, return 0 if all active plugins have the cnt 902*7c478bd9Sstevel@tonic-gate * policy set, else 1. 0 is also returned if the input is a control 903*7c478bd9Sstevel@tonic-gate * message. (aub_buf is aligned on a 64 bit boundary, so casting 904*7c478bd9Sstevel@tonic-gate * it to an integer works just fine.) 905*7c478bd9Sstevel@tonic-gate */ 906*7c478bd9Sstevel@tonic-gate static int 907*7c478bd9Sstevel@tonic-gate queue_buffer(au_dbuf_t *kl) 908*7c478bd9Sstevel@tonic-gate { 909*7c478bd9Sstevel@tonic-gate plugin_t *p; 910*7c478bd9Sstevel@tonic-gate audit_rec_t *b_copy; 911*7c478bd9Sstevel@tonic-gate audit_q_t *q_copy; 912*7c478bd9Sstevel@tonic-gate boolean_t referenced = 0; 913*7c478bd9Sstevel@tonic-gate static char *invalid_msg = "invalid audit record discarded"; 914*7c478bd9Sstevel@tonic-gate static char *invalid_control = 915*7c478bd9Sstevel@tonic-gate "invalid audit control discarded"; 916*7c478bd9Sstevel@tonic-gate 917*7c478bd9Sstevel@tonic-gate static audit_rec_t *alt_b_copy = NULL; 918*7c478bd9Sstevel@tonic-gate static size_t alt_length; 919*7c478bd9Sstevel@tonic-gate static size_t alt_offset; 920*7c478bd9Sstevel@tonic-gate 921*7c478bd9Sstevel@tonic-gate /* 922*7c478bd9Sstevel@tonic-gate * the buffer may be a kernel -> auditd message. (only 923*7c478bd9Sstevel@tonic-gate * the policy change message exists so far.) 924*7c478bd9Sstevel@tonic-gate */ 925*7c478bd9Sstevel@tonic-gate 926*7c478bd9Sstevel@tonic-gate if ((kl->aub_type & AU_DBUF_NOTIFY) != 0) { 927*7c478bd9Sstevel@tonic-gate uint32_t control; 928*7c478bd9Sstevel@tonic-gate 929*7c478bd9Sstevel@tonic-gate control = kl->aub_type & ~AU_DBUF_NOTIFY; 930*7c478bd9Sstevel@tonic-gate switch (control) { 931*7c478bd9Sstevel@tonic-gate case AU_DBUF_POLICY: 932*7c478bd9Sstevel@tonic-gate /* LINTED */ 933*7c478bd9Sstevel@tonic-gate policy_update(*(uint32_t *)kl->aub_buf); 934*7c478bd9Sstevel@tonic-gate break; 935*7c478bd9Sstevel@tonic-gate case AU_DBUF_SHUTDOWN: 936*7c478bd9Sstevel@tonic-gate (void) kill(getpid(), AU_SIG_DISABLE); 937*7c478bd9Sstevel@tonic-gate DPRINT((dbfp, "AU_DBUF_SHUTDOWN message\n")); 938*7c478bd9Sstevel@tonic-gate break; 939*7c478bd9Sstevel@tonic-gate default: 940*7c478bd9Sstevel@tonic-gate warn_or_fatal(0, gettext(invalid_control)); 941*7c478bd9Sstevel@tonic-gate break; 942*7c478bd9Sstevel@tonic-gate } 943*7c478bd9Sstevel@tonic-gate return (0); 944*7c478bd9Sstevel@tonic-gate } 945*7c478bd9Sstevel@tonic-gate /* 946*7c478bd9Sstevel@tonic-gate * The test for valid continuation/completion may fail. Need to 947*7c478bd9Sstevel@tonic-gate * assume the failure was earlier and that this buffer may 948*7c478bd9Sstevel@tonic-gate * be a valid first or complete buffer after discarding the 949*7c478bd9Sstevel@tonic-gate * incomplete record 950*7c478bd9Sstevel@tonic-gate */ 951*7c478bd9Sstevel@tonic-gate 952*7c478bd9Sstevel@tonic-gate if (alt_b_copy != NULL) { 953*7c478bd9Sstevel@tonic-gate if ((kl->aub_type == AU_DBUF_FIRST) || 954*7c478bd9Sstevel@tonic-gate (kl->aub_type == AU_DBUF_COMPLETE)) { 955*7c478bd9Sstevel@tonic-gate DPRINT((dbfp, "copy is not null, partial is %d\n", 956*7c478bd9Sstevel@tonic-gate kl->aub_type)); 957*7c478bd9Sstevel@tonic-gate bpool_return(alt_b_copy); 958*7c478bd9Sstevel@tonic-gate warn_or_fatal(0, gettext(invalid_msg)); 959*7c478bd9Sstevel@tonic-gate alt_b_copy = NULL; 960*7c478bd9Sstevel@tonic-gate } 961*7c478bd9Sstevel@tonic-gate } 962*7c478bd9Sstevel@tonic-gate if (alt_b_copy != NULL) { /* continue collecting a long record */ 963*7c478bd9Sstevel@tonic-gate if (kl->aub_size + alt_offset > alt_length) { 964*7c478bd9Sstevel@tonic-gate bpool_return(alt_b_copy); 965*7c478bd9Sstevel@tonic-gate alt_b_copy = NULL; 966*7c478bd9Sstevel@tonic-gate warn_or_fatal(0, gettext(invalid_msg)); 967*7c478bd9Sstevel@tonic-gate return (0); 968*7c478bd9Sstevel@tonic-gate } 969*7c478bd9Sstevel@tonic-gate (void) memcpy(alt_b_copy->abq_buffer + alt_offset, kl->aub_buf, 970*7c478bd9Sstevel@tonic-gate kl->aub_size); 971*7c478bd9Sstevel@tonic-gate alt_offset += kl->aub_size; 972*7c478bd9Sstevel@tonic-gate if (kl->aub_type == AU_DBUF_MIDDLE) 973*7c478bd9Sstevel@tonic-gate return (0); 974*7c478bd9Sstevel@tonic-gate b_copy = alt_b_copy; 975*7c478bd9Sstevel@tonic-gate alt_b_copy = NULL; 976*7c478bd9Sstevel@tonic-gate b_copy->abq_data_len = alt_length; 977*7c478bd9Sstevel@tonic-gate } else if (kl->aub_type == AU_DBUF_FIRST) { 978*7c478bd9Sstevel@tonic-gate /* first buffer of a multiple buffer record */ 979*7c478bd9Sstevel@tonic-gate alt_length = getlen(kl->aub_buf); 980*7c478bd9Sstevel@tonic-gate if ((alt_length < MIN_RECORD_SIZE) || 981*7c478bd9Sstevel@tonic-gate (alt_length <= kl->aub_size)) { 982*7c478bd9Sstevel@tonic-gate warn_or_fatal(0, gettext(invalid_msg)); 983*7c478bd9Sstevel@tonic-gate return (0); 984*7c478bd9Sstevel@tonic-gate } 985*7c478bd9Sstevel@tonic-gate alt_b_copy = bpool_withdraw(kl->aub_buf, kl->aub_size, 986*7c478bd9Sstevel@tonic-gate alt_length); 987*7c478bd9Sstevel@tonic-gate 988*7c478bd9Sstevel@tonic-gate if (alt_b_copy == NULL) 989*7c478bd9Sstevel@tonic-gate return (policy_is_block()); 990*7c478bd9Sstevel@tonic-gate 991*7c478bd9Sstevel@tonic-gate alt_offset = kl->aub_size; 992*7c478bd9Sstevel@tonic-gate return (0); 993*7c478bd9Sstevel@tonic-gate } else { /* one buffer, one record -- the basic case */ 994*7c478bd9Sstevel@tonic-gate if (kl->aub_type != AU_DBUF_COMPLETE) { 995*7c478bd9Sstevel@tonic-gate DPRINT((dbfp, "copy is null, partial is %d\n", 996*7c478bd9Sstevel@tonic-gate kl->aub_type)); 997*7c478bd9Sstevel@tonic-gate warn_or_fatal(0, gettext(invalid_msg)); 998*7c478bd9Sstevel@tonic-gate return (0); /* tossed */ 999*7c478bd9Sstevel@tonic-gate } 1000*7c478bd9Sstevel@tonic-gate b_copy = bpool_withdraw(kl->aub_buf, kl->aub_size, 1001*7c478bd9Sstevel@tonic-gate kl->aub_size); 1002*7c478bd9Sstevel@tonic-gate 1003*7c478bd9Sstevel@tonic-gate if (b_copy == NULL) 1004*7c478bd9Sstevel@tonic-gate return (policy_is_block()); 1005*7c478bd9Sstevel@tonic-gate } 1006*7c478bd9Sstevel@tonic-gate 1007*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&plugin_mutex); 1008*7c478bd9Sstevel@tonic-gate p = plugin_head; 1009*7c478bd9Sstevel@tonic-gate while (p != NULL) { 1010*7c478bd9Sstevel@tonic-gate if (!p->plg_removed) { 1011*7c478bd9Sstevel@tonic-gate /* 1012*7c478bd9Sstevel@tonic-gate * Link the record buffer to the input queues. 1013*7c478bd9Sstevel@tonic-gate * To avoid a race, it is necessary to wait 1014*7c478bd9Sstevel@tonic-gate * until all reference count increments 1015*7c478bd9Sstevel@tonic-gate * are complete before queueing q_copy. 1016*7c478bd9Sstevel@tonic-gate */ 1017*7c478bd9Sstevel@tonic-gate audit_incr_ref(&b_refcnt_lock, b_copy); 1018*7c478bd9Sstevel@tonic-gate 1019*7c478bd9Sstevel@tonic-gate q_copy = qpool_withdraw(p); 1020*7c478bd9Sstevel@tonic-gate q_copy->aqq_sequence = p->plg_sequence++; 1021*7c478bd9Sstevel@tonic-gate q_copy->aqq_data = b_copy; 1022*7c478bd9Sstevel@tonic-gate 1023*7c478bd9Sstevel@tonic-gate p->plg_save_q_copy = q_copy; /* enqueue below */ 1024*7c478bd9Sstevel@tonic-gate referenced = 1; 1025*7c478bd9Sstevel@tonic-gate } else 1026*7c478bd9Sstevel@tonic-gate p->plg_save_q_copy = NULL; 1027*7c478bd9Sstevel@tonic-gate p = p->plg_next; 1028*7c478bd9Sstevel@tonic-gate } 1029*7c478bd9Sstevel@tonic-gate /* 1030*7c478bd9Sstevel@tonic-gate * now that the reference count is updated, queue it. 1031*7c478bd9Sstevel@tonic-gate */ 1032*7c478bd9Sstevel@tonic-gate if (referenced) { 1033*7c478bd9Sstevel@tonic-gate p = plugin_head; 1034*7c478bd9Sstevel@tonic-gate while ((p != NULL) && (p->plg_save_q_copy != NULL)) { 1035*7c478bd9Sstevel@tonic-gate audit_enqueue(&(p->plg_queue), p->plg_save_q_copy); 1036*7c478bd9Sstevel@tonic-gate (void) pthread_cond_signal(&(p->plg_cv)); 1037*7c478bd9Sstevel@tonic-gate p->plg_queued++; 1038*7c478bd9Sstevel@tonic-gate p = p->plg_next; 1039*7c478bd9Sstevel@tonic-gate } 1040*7c478bd9Sstevel@tonic-gate } else 1041*7c478bd9Sstevel@tonic-gate bpool_return(b_copy); 1042*7c478bd9Sstevel@tonic-gate 1043*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&plugin_mutex); 1044*7c478bd9Sstevel@tonic-gate 1045*7c478bd9Sstevel@tonic-gate return (0); 1046*7c478bd9Sstevel@tonic-gate } 1047*7c478bd9Sstevel@tonic-gate 1048*7c478bd9Sstevel@tonic-gate /* 1049*7c478bd9Sstevel@tonic-gate * wait_a_while() -- timed wait in the door server to allow output 1050*7c478bd9Sstevel@tonic-gate * time to catch up. 1051*7c478bd9Sstevel@tonic-gate */ 1052*7c478bd9Sstevel@tonic-gate static void 1053*7c478bd9Sstevel@tonic-gate wait_a_while() { 1054*7c478bd9Sstevel@tonic-gate struct timespec delay = {0, 500000000}; /* 1/2 second */; 1055*7c478bd9Sstevel@tonic-gate 1056*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&(in_thr.thd_mutex)); 1057*7c478bd9Sstevel@tonic-gate in_thr.thd_waiting = 1; 1058*7c478bd9Sstevel@tonic-gate (void) pthread_cond_reltimedwait_np(&(in_thr.thd_cv), 1059*7c478bd9Sstevel@tonic-gate &(in_thr.thd_mutex), &delay); 1060*7c478bd9Sstevel@tonic-gate in_thr.thd_waiting = 0; 1061*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&(in_thr.thd_mutex)); 1062*7c478bd9Sstevel@tonic-gate } 1063*7c478bd9Sstevel@tonic-gate 1064*7c478bd9Sstevel@tonic-gate /* 1065*7c478bd9Sstevel@tonic-gate * adjust_priority() -- check queue and pools and adjust the priority 1066*7c478bd9Sstevel@tonic-gate * for process() accordingly. If we're way ahead of output, do a 1067*7c478bd9Sstevel@tonic-gate * timed wait as well. 1068*7c478bd9Sstevel@tonic-gate */ 1069*7c478bd9Sstevel@tonic-gate static void 1070*7c478bd9Sstevel@tonic-gate adjust_priority() { 1071*7c478bd9Sstevel@tonic-gate int queue_near_full; 1072*7c478bd9Sstevel@tonic-gate plugin_t *p; 1073*7c478bd9Sstevel@tonic-gate int queue_size; 1074*7c478bd9Sstevel@tonic-gate struct sched_param param; 1075*7c478bd9Sstevel@tonic-gate 1076*7c478bd9Sstevel@tonic-gate queue_near_full = 0; 1077*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&plugin_mutex); 1078*7c478bd9Sstevel@tonic-gate p = plugin_head; 1079*7c478bd9Sstevel@tonic-gate while (p != NULL) { 1080*7c478bd9Sstevel@tonic-gate queue_size = audit_queue_size(&(p->plg_queue)); 1081*7c478bd9Sstevel@tonic-gate if (queue_size > p->plg_q_threshold) { 1082*7c478bd9Sstevel@tonic-gate if (p->plg_priority != HIGH_PRIORITY) { 1083*7c478bd9Sstevel@tonic-gate p->plg_priority = 1084*7c478bd9Sstevel@tonic-gate param.sched_priority = 1085*7c478bd9Sstevel@tonic-gate HIGH_PRIORITY; 1086*7c478bd9Sstevel@tonic-gate (void) pthread_setschedparam(p->plg_tid, 1087*7c478bd9Sstevel@tonic-gate SCHED_OTHER, ¶m); 1088*7c478bd9Sstevel@tonic-gate } 1089*7c478bd9Sstevel@tonic-gate if (queue_size > p->plg_qmax - p->plg_qmin) { 1090*7c478bd9Sstevel@tonic-gate queue_near_full = 1; 1091*7c478bd9Sstevel@tonic-gate break; 1092*7c478bd9Sstevel@tonic-gate } 1093*7c478bd9Sstevel@tonic-gate } 1094*7c478bd9Sstevel@tonic-gate p = p->plg_next; 1095*7c478bd9Sstevel@tonic-gate } 1096*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&plugin_mutex); 1097*7c478bd9Sstevel@tonic-gate 1098*7c478bd9Sstevel@tonic-gate if (queue_near_full) { 1099*7c478bd9Sstevel@tonic-gate DPRINT((dbfp, 1100*7c478bd9Sstevel@tonic-gate "adjust_priority: input taking a short break\n")); 1101*7c478bd9Sstevel@tonic-gate wait_a_while(); 1102*7c478bd9Sstevel@tonic-gate DPRINT((dbfp, 1103*7c478bd9Sstevel@tonic-gate "adjust_priority: input back from my break\n")); 1104*7c478bd9Sstevel@tonic-gate } 1105*7c478bd9Sstevel@tonic-gate } 1106*7c478bd9Sstevel@tonic-gate 1107*7c478bd9Sstevel@tonic-gate /* 1108*7c478bd9Sstevel@tonic-gate * input() is a door server; it blocks if any plugins have full queues 1109*7c478bd9Sstevel@tonic-gate * with the continue policy off. (auditconfig -policy -cnt) 1110*7c478bd9Sstevel@tonic-gate * 1111*7c478bd9Sstevel@tonic-gate * input() is called synchronously from c2audit and is NOT 1112*7c478bd9Sstevel@tonic-gate * reentrant due to the (unprotected) static variables in 1113*7c478bd9Sstevel@tonic-gate * queue_buffer(). If multiple clients are created, a context 1114*7c478bd9Sstevel@tonic-gate * structure will be required for queue_buffer. 1115*7c478bd9Sstevel@tonic-gate * 1116*7c478bd9Sstevel@tonic-gate * timedwait is used when input() gets too far ahead of process(); 1117*7c478bd9Sstevel@tonic-gate * the wait terminates either when the set time expires or when 1118*7c478bd9Sstevel@tonic-gate * process() signals that it has nearly caught up. 1119*7c478bd9Sstevel@tonic-gate */ 1120*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1121*7c478bd9Sstevel@tonic-gate static void 1122*7c478bd9Sstevel@tonic-gate input(void *cookie, void *argp, int arg_size, door_desc_t *dp, 1123*7c478bd9Sstevel@tonic-gate int n_descriptors) 1124*7c478bd9Sstevel@tonic-gate { 1125*7c478bd9Sstevel@tonic-gate int is_blocked; 1126*7c478bd9Sstevel@tonic-gate plugin_t *p; 1127*7c478bd9Sstevel@tonic-gate #if DEBUG 1128*7c478bd9Sstevel@tonic-gate int loop_count = 0; 1129*7c478bd9Sstevel@tonic-gate static int call_counter = 0; 1130*7c478bd9Sstevel@tonic-gate #endif 1131*7c478bd9Sstevel@tonic-gate if (argp == NULL) { 1132*7c478bd9Sstevel@tonic-gate warn_or_fatal(0, 1133*7c478bd9Sstevel@tonic-gate gettext("invalid data received from c2audit\n")); 1134*7c478bd9Sstevel@tonic-gate goto input_exit; 1135*7c478bd9Sstevel@tonic-gate } 1136*7c478bd9Sstevel@tonic-gate DPRINT((dbfp, "%d input new buffer: length=%u, " 1137*7c478bd9Sstevel@tonic-gate "partial=%u, arg_size=%d\n", 1138*7c478bd9Sstevel@tonic-gate ++call_counter, ((au_dbuf_t *)argp)->aub_size, 1139*7c478bd9Sstevel@tonic-gate ((au_dbuf_t *)argp)->aub_type, arg_size)); 1140*7c478bd9Sstevel@tonic-gate 1141*7c478bd9Sstevel@tonic-gate if (((au_dbuf_t *)argp)->aub_size < 1) { 1142*7c478bd9Sstevel@tonic-gate warn_or_fatal(0, 1143*7c478bd9Sstevel@tonic-gate gettext("invalid data length received from c2audit\n")); 1144*7c478bd9Sstevel@tonic-gate goto input_exit; 1145*7c478bd9Sstevel@tonic-gate } 1146*7c478bd9Sstevel@tonic-gate /* 1147*7c478bd9Sstevel@tonic-gate * is_blocked is true only if one or more plugins have "no 1148*7c478bd9Sstevel@tonic-gate * continue" (-cnt) set and one of those has a full queue. 1149*7c478bd9Sstevel@tonic-gate * All plugins block until success is met. 1150*7c478bd9Sstevel@tonic-gate */ 1151*7c478bd9Sstevel@tonic-gate for (;;) { 1152*7c478bd9Sstevel@tonic-gate DPRINT((dbfp, "%d input is calling queue_buffer\n", 1153*7c478bd9Sstevel@tonic-gate call_counter)); 1154*7c478bd9Sstevel@tonic-gate 1155*7c478bd9Sstevel@tonic-gate is_blocked = queue_buffer((au_dbuf_t *)argp); 1156*7c478bd9Sstevel@tonic-gate 1157*7c478bd9Sstevel@tonic-gate if (!is_blocked) { 1158*7c478bd9Sstevel@tonic-gate adjust_priority(); 1159*7c478bd9Sstevel@tonic-gate break; 1160*7c478bd9Sstevel@tonic-gate } else { 1161*7c478bd9Sstevel@tonic-gate DPRINT((dbfp, 1162*7c478bd9Sstevel@tonic-gate "%d input blocked (loop=%d)\n", 1163*7c478bd9Sstevel@tonic-gate call_counter, loop_count)); 1164*7c478bd9Sstevel@tonic-gate 1165*7c478bd9Sstevel@tonic-gate wait_a_while(); 1166*7c478bd9Sstevel@tonic-gate 1167*7c478bd9Sstevel@tonic-gate DPRINT((dbfp, "%d input unblocked (loop=%d)\n", 1168*7c478bd9Sstevel@tonic-gate call_counter, loop_count)); 1169*7c478bd9Sstevel@tonic-gate } 1170*7c478bd9Sstevel@tonic-gate #if DEBUG 1171*7c478bd9Sstevel@tonic-gate loop_count++; 1172*7c478bd9Sstevel@tonic-gate #endif 1173*7c478bd9Sstevel@tonic-gate } 1174*7c478bd9Sstevel@tonic-gate input_exit: 1175*7c478bd9Sstevel@tonic-gate p = plugin_head; 1176*7c478bd9Sstevel@tonic-gate while (p != NULL) { 1177*7c478bd9Sstevel@tonic-gate (void) pthread_cond_signal(&(p->plg_cv)); 1178*7c478bd9Sstevel@tonic-gate p = p->plg_next; 1179*7c478bd9Sstevel@tonic-gate } 1180*7c478bd9Sstevel@tonic-gate ((au_dbuf_t *)argp)->aub_size = 0; /* return code */ 1181*7c478bd9Sstevel@tonic-gate (void) door_return(argp, sizeof (uint64_t), NULL, 0); 1182*7c478bd9Sstevel@tonic-gate } 1183*7c478bd9Sstevel@tonic-gate 1184*7c478bd9Sstevel@tonic-gate /* 1185*7c478bd9Sstevel@tonic-gate * process() -- pass a buffer to a plugin 1186*7c478bd9Sstevel@tonic-gate */ 1187*7c478bd9Sstevel@tonic-gate static void 1188*7c478bd9Sstevel@tonic-gate process(plugin_t *p) 1189*7c478bd9Sstevel@tonic-gate { 1190*7c478bd9Sstevel@tonic-gate int rc; 1191*7c478bd9Sstevel@tonic-gate audit_rec_t *b_node; 1192*7c478bd9Sstevel@tonic-gate audit_q_t *q_node; 1193*7c478bd9Sstevel@tonic-gate auditd_rc_t plugrc; 1194*7c478bd9Sstevel@tonic-gate char *error_string; 1195*7c478bd9Sstevel@tonic-gate struct timespec delay; 1196*7c478bd9Sstevel@tonic-gate int sendsignal; 1197*7c478bd9Sstevel@tonic-gate int queue_len; 1198*7c478bd9Sstevel@tonic-gate struct sched_param param; 1199*7c478bd9Sstevel@tonic-gate 1200*7c478bd9Sstevel@tonic-gate DPRINT((dbfp, "%s is thread %d\n", p->plg_path, p->plg_tid)); 1201*7c478bd9Sstevel@tonic-gate p->plg_priority = param.sched_priority = BASE_PRIORITY; 1202*7c478bd9Sstevel@tonic-gate (void) pthread_setschedparam(p->plg_tid, SCHED_OTHER, ¶m); 1203*7c478bd9Sstevel@tonic-gate 1204*7c478bd9Sstevel@tonic-gate delay.tv_nsec = 0; 1205*7c478bd9Sstevel@tonic-gate 1206*7c478bd9Sstevel@tonic-gate for (;;) { 1207*7c478bd9Sstevel@tonic-gate retry_mode: 1208*7c478bd9Sstevel@tonic-gate 1209*7c478bd9Sstevel@tonic-gate while (audit_dequeue(&(p->plg_queue), (void *)&q_node) != 0) { 1210*7c478bd9Sstevel@tonic-gate DUMP("process", p, p->plg_last_seq_out, "blocked"); 1211*7c478bd9Sstevel@tonic-gate (void) pthread_cond_signal(&(in_thr.thd_cv)); 1212*7c478bd9Sstevel@tonic-gate 1213*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&(p->plg_mutex)); 1214*7c478bd9Sstevel@tonic-gate p->plg_waiting++; 1215*7c478bd9Sstevel@tonic-gate (void) pthread_cond_wait(&(p->plg_cv), 1216*7c478bd9Sstevel@tonic-gate &(p->plg_mutex)); 1217*7c478bd9Sstevel@tonic-gate p->plg_waiting--; 1218*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&(p->plg_mutex)); 1219*7c478bd9Sstevel@tonic-gate 1220*7c478bd9Sstevel@tonic-gate if (p->plg_removed) 1221*7c478bd9Sstevel@tonic-gate break; 1222*7c478bd9Sstevel@tonic-gate 1223*7c478bd9Sstevel@tonic-gate DUMP("process", p, p->plg_last_seq_out, "unblocked"); 1224*7c478bd9Sstevel@tonic-gate } 1225*7c478bd9Sstevel@tonic-gate if (p->plg_removed) 1226*7c478bd9Sstevel@tonic-gate break; 1227*7c478bd9Sstevel@tonic-gate #if DEBUG 1228*7c478bd9Sstevel@tonic-gate if (q_node->aqq_sequence != p->plg_last_seq_out + 1) 1229*7c478bd9Sstevel@tonic-gate (void) fprintf(dbfp, 1230*7c478bd9Sstevel@tonic-gate "process(%d): buffer sequence=%u but prev=%u\n", 1231*7c478bd9Sstevel@tonic-gate p->plg_tid, q_node->aqq_sequence, 1232*7c478bd9Sstevel@tonic-gate p->plg_last_seq_out); 1233*7c478bd9Sstevel@tonic-gate #endif 1234*7c478bd9Sstevel@tonic-gate error_string = NULL; 1235*7c478bd9Sstevel@tonic-gate 1236*7c478bd9Sstevel@tonic-gate b_node = q_node->aqq_data; 1237*7c478bd9Sstevel@tonic-gate plugrc = p->plg_fplugin(b_node->abq_buffer, 1238*7c478bd9Sstevel@tonic-gate b_node->abq_data_len, 1239*7c478bd9Sstevel@tonic-gate q_node->aqq_sequence, &error_string); 1240*7c478bd9Sstevel@tonic-gate #if DEBUG 1241*7c478bd9Sstevel@tonic-gate p->plg_last_seq_out = q_node->aqq_sequence; 1242*7c478bd9Sstevel@tonic-gate #endif 1243*7c478bd9Sstevel@tonic-gate switch (plugrc) { 1244*7c478bd9Sstevel@tonic-gate case AUDITD_RETRY: 1245*7c478bd9Sstevel@tonic-gate report_error(plugrc, error_string, p->plg_path); 1246*7c478bd9Sstevel@tonic-gate free(error_string); 1247*7c478bd9Sstevel@tonic-gate error_string = NULL; 1248*7c478bd9Sstevel@tonic-gate 1249*7c478bd9Sstevel@tonic-gate DPRINT((dbfp, "process(%d) AUDITD_RETRY returned." 1250*7c478bd9Sstevel@tonic-gate " cnt=%d (if 1, enter retry)\n", 1251*7c478bd9Sstevel@tonic-gate p->plg_tid, p->plg_cnt)); 1252*7c478bd9Sstevel@tonic-gate 1253*7c478bd9Sstevel@tonic-gate if (p->plg_cnt) /* if cnt is on, lose the buffer */ 1254*7c478bd9Sstevel@tonic-gate break; 1255*7c478bd9Sstevel@tonic-gate 1256*7c478bd9Sstevel@tonic-gate delay.tv_sec = p->plg_retry_time; 1257*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&(p->plg_mutex)); 1258*7c478bd9Sstevel@tonic-gate p->plg_waiting++; 1259*7c478bd9Sstevel@tonic-gate (void) pthread_cond_reltimedwait_np(&(p->plg_cv), 1260*7c478bd9Sstevel@tonic-gate &(p->plg_mutex), &delay); 1261*7c478bd9Sstevel@tonic-gate p->plg_waiting--; 1262*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&(p->plg_mutex)); 1263*7c478bd9Sstevel@tonic-gate 1264*7c478bd9Sstevel@tonic-gate DPRINT((dbfp, "left retry mode for %d\n", p->plg_tid)); 1265*7c478bd9Sstevel@tonic-gate goto retry_mode; 1266*7c478bd9Sstevel@tonic-gate 1267*7c478bd9Sstevel@tonic-gate case AUDITD_SUCCESS: 1268*7c478bd9Sstevel@tonic-gate p->plg_output++; 1269*7c478bd9Sstevel@tonic-gate break; 1270*7c478bd9Sstevel@tonic-gate default: 1271*7c478bd9Sstevel@tonic-gate report_error(plugrc, error_string, p->plg_path); 1272*7c478bd9Sstevel@tonic-gate free(error_string); 1273*7c478bd9Sstevel@tonic-gate error_string = NULL; 1274*7c478bd9Sstevel@tonic-gate break; 1275*7c478bd9Sstevel@tonic-gate } /* end switch */ 1276*7c478bd9Sstevel@tonic-gate bpool_return(b_node); 1277*7c478bd9Sstevel@tonic-gate qpool_return(p, q_node); 1278*7c478bd9Sstevel@tonic-gate 1279*7c478bd9Sstevel@tonic-gate sendsignal = 0; 1280*7c478bd9Sstevel@tonic-gate queue_len = audit_queue_size(&(p->plg_queue)); 1281*7c478bd9Sstevel@tonic-gate 1282*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&(in_thr.thd_mutex)); 1283*7c478bd9Sstevel@tonic-gate if (in_thr.thd_waiting && (queue_len > p->plg_qmin) && 1284*7c478bd9Sstevel@tonic-gate (queue_len < p->plg_q_threshold)) 1285*7c478bd9Sstevel@tonic-gate sendsignal = 1; 1286*7c478bd9Sstevel@tonic-gate 1287*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&(in_thr.thd_mutex)); 1288*7c478bd9Sstevel@tonic-gate 1289*7c478bd9Sstevel@tonic-gate if (sendsignal) { 1290*7c478bd9Sstevel@tonic-gate (void) pthread_cond_signal(&(in_thr.thd_cv)); 1291*7c478bd9Sstevel@tonic-gate /* 1292*7c478bd9Sstevel@tonic-gate * sched_yield(); does not help 1293*7c478bd9Sstevel@tonic-gate * performance and in artificial tests 1294*7c478bd9Sstevel@tonic-gate * (high sustained volume) appears to 1295*7c478bd9Sstevel@tonic-gate * hurt by adding wide variability in 1296*7c478bd9Sstevel@tonic-gate * the results. 1297*7c478bd9Sstevel@tonic-gate */ 1298*7c478bd9Sstevel@tonic-gate } else if ((p->plg_priority < BASE_PRIORITY) && 1299*7c478bd9Sstevel@tonic-gate (queue_len < p->plg_q_threshold)) { 1300*7c478bd9Sstevel@tonic-gate p->plg_priority = param.sched_priority = 1301*7c478bd9Sstevel@tonic-gate BASE_PRIORITY; 1302*7c478bd9Sstevel@tonic-gate (void) pthread_setschedparam(p->plg_tid, SCHED_OTHER, 1303*7c478bd9Sstevel@tonic-gate ¶m); 1304*7c478bd9Sstevel@tonic-gate } 1305*7c478bd9Sstevel@tonic-gate } /* end for (;;) */ 1306*7c478bd9Sstevel@tonic-gate DUMP("process", p, p->plg_last_seq_out, "exit"); 1307*7c478bd9Sstevel@tonic-gate error_string = NULL; 1308*7c478bd9Sstevel@tonic-gate if ((rc = p->plg_fplugin_close(&error_string)) != 1309*7c478bd9Sstevel@tonic-gate AUDITD_SUCCESS) 1310*7c478bd9Sstevel@tonic-gate report_error(rc, error_string, p->plg_path); 1311*7c478bd9Sstevel@tonic-gate 1312*7c478bd9Sstevel@tonic-gate free(error_string); 1313*7c478bd9Sstevel@tonic-gate 1314*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&plugin_mutex); 1315*7c478bd9Sstevel@tonic-gate (void) unload_plugin(p); 1316*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&plugin_mutex); 1317*7c478bd9Sstevel@tonic-gate } 1318