1911106dfSjm199354 /* 2911106dfSjm199354 * CDDL HEADER START 3911106dfSjm199354 * 4911106dfSjm199354 * The contents of this file are subject to the terms of the 5911106dfSjm199354 * Common Development and Distribution License (the "License"). 6911106dfSjm199354 * You may not use this file except in compliance with the License. 7911106dfSjm199354 * 8911106dfSjm199354 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9911106dfSjm199354 * or http://www.opensolaris.org/os/licensing. 10911106dfSjm199354 * See the License for the specific language governing permissions 11911106dfSjm199354 * and limitations under the License. 12911106dfSjm199354 * 13911106dfSjm199354 * When distributing Covered Code, include this CDDL HEADER in each 14911106dfSjm199354 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15911106dfSjm199354 * If applicable, add the following below this CDDL HEADER, with the 16911106dfSjm199354 * fields enclosed by brackets "[]" replaced with your own identifying 17911106dfSjm199354 * information: Portions Copyright [yyyy] [name of copyright owner] 18911106dfSjm199354 * 19911106dfSjm199354 * CDDL HEADER END 20911106dfSjm199354 */ 21911106dfSjm199354 /* 22*bfc848c6Sjm199354 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23911106dfSjm199354 * Use is subject to license terms. 24911106dfSjm199354 */ 25911106dfSjm199354 26911106dfSjm199354 #pragma ident "%Z%%M% %I% %E% SMI" 27911106dfSjm199354 28911106dfSjm199354 /* 29911106dfSjm199354 * Implementation of the vscan statistics interface 30911106dfSjm199354 */ 31911106dfSjm199354 32911106dfSjm199354 #include <stdio.h> 33911106dfSjm199354 #include <stdlib.h> 34911106dfSjm199354 #include <unistd.h> 35911106dfSjm199354 #include <string.h> 36911106dfSjm199354 #include <syslog.h> 37911106dfSjm199354 #include <pthread.h> 38911106dfSjm199354 #include <door.h> 39911106dfSjm199354 #include <pwd.h> 40911106dfSjm199354 #include <auth_attr.h> 41911106dfSjm199354 #include <secdb.h> 42911106dfSjm199354 #include <sys/stat.h> 43911106dfSjm199354 #include <fcntl.h> 44911106dfSjm199354 #include "vs_incl.h" 45911106dfSjm199354 46911106dfSjm199354 47911106dfSjm199354 /* local data */ 48911106dfSjm199354 static vs_stats_t vscan_stats; 49911106dfSjm199354 static int vs_stats_door_cookie; 50911106dfSjm199354 static int vs_stats_door_fd = -1; 51911106dfSjm199354 static pthread_mutex_t vs_stats_mutex = PTHREAD_MUTEX_INITIALIZER; 52911106dfSjm199354 53911106dfSjm199354 54911106dfSjm199354 /* function prototype */ 55911106dfSjm199354 static int vs_stats_check_auth(void); 56*bfc848c6Sjm199354 static void vs_stats_reset(void); 57911106dfSjm199354 static void vs_stats_door_call(void *, char *, size_t, door_desc_t *, uint_t); 58911106dfSjm199354 59911106dfSjm199354 60911106dfSjm199354 /* 61911106dfSjm199354 * vs_stats_init 62911106dfSjm199354 * 63911106dfSjm199354 * Invoked on daemon load and unload 64911106dfSjm199354 */ 65911106dfSjm199354 int 66911106dfSjm199354 vs_stats_init(void) 67911106dfSjm199354 { 68911106dfSjm199354 (void) pthread_mutex_lock(&vs_stats_mutex); 69911106dfSjm199354 70911106dfSjm199354 (void) memset(&vscan_stats, 0, sizeof (vs_stats_t)); 71911106dfSjm199354 72911106dfSjm199354 /* door initialization */ 73911106dfSjm199354 if ((vs_stats_door_fd = door_create(vs_stats_door_call, 74911106dfSjm199354 &vs_stats_door_cookie, (DOOR_UNREF | DOOR_REFUSE_DESC))) < 0) { 75911106dfSjm199354 vs_stats_door_fd = -1; 76911106dfSjm199354 } else { 77911106dfSjm199354 (void) fdetach(VS_STATS_DOOR_NAME); 78911106dfSjm199354 if (fattach(vs_stats_door_fd, VS_STATS_DOOR_NAME) < 0) { 79911106dfSjm199354 (void) door_revoke(vs_stats_door_fd); 80911106dfSjm199354 vs_stats_door_fd = -1; 81911106dfSjm199354 } 82911106dfSjm199354 } 83911106dfSjm199354 84911106dfSjm199354 (void) pthread_mutex_unlock(&vs_stats_mutex); 85911106dfSjm199354 86911106dfSjm199354 return ((vs_stats_door_fd == -1) ? -1 : 0); 87911106dfSjm199354 } 88911106dfSjm199354 89911106dfSjm199354 90911106dfSjm199354 /* 91911106dfSjm199354 * vs_stats_fini 92911106dfSjm199354 * 93911106dfSjm199354 * Invoked on daemon unload 94911106dfSjm199354 */ 95911106dfSjm199354 void 96911106dfSjm199354 vs_stats_fini(void) 97911106dfSjm199354 { 98911106dfSjm199354 (void) pthread_mutex_lock(&vs_stats_mutex); 99911106dfSjm199354 100911106dfSjm199354 /* door termination */ 101911106dfSjm199354 if (vs_stats_door_fd != -1) 102911106dfSjm199354 (void) door_revoke(vs_stats_door_fd); 103911106dfSjm199354 vs_stats_door_fd = -1; 104911106dfSjm199354 105911106dfSjm199354 (void) fdetach(VS_STATS_DOOR_NAME); 106911106dfSjm199354 (void) unlink(VS_STATS_DOOR_NAME); 107911106dfSjm199354 108911106dfSjm199354 (void) pthread_mutex_unlock(&vs_stats_mutex); 109911106dfSjm199354 } 110911106dfSjm199354 111911106dfSjm199354 112911106dfSjm199354 /* 113911106dfSjm199354 * vs_stats_check_auth 114911106dfSjm199354 * 115911106dfSjm199354 * Returns: 0 caller authorized to reset stats 116911106dfSjm199354 * -1 caller not authorized to reset stats 117911106dfSjm199354 */ 118911106dfSjm199354 static int 119911106dfSjm199354 vs_stats_check_auth() 120911106dfSjm199354 { 121911106dfSjm199354 ucred_t *uc = NULL; 122911106dfSjm199354 uid_t uid; 123911106dfSjm199354 struct passwd *pw; 124911106dfSjm199354 125911106dfSjm199354 if (door_ucred(&uc) != 0) 126911106dfSjm199354 return (-1); 127911106dfSjm199354 128911106dfSjm199354 if (((uid = ucred_getsuid(uc)) == (uid_t)-1) || 129911106dfSjm199354 ((pw = getpwuid(uid)) == NULL) || 130911106dfSjm199354 (chkauthattr(VS_VALUE_AUTH, pw->pw_name) != 1)) { 131911106dfSjm199354 ucred_free(uc); 132911106dfSjm199354 return (-1); 133911106dfSjm199354 } 134911106dfSjm199354 135911106dfSjm199354 ucred_free(uc); 136911106dfSjm199354 return (0); 137911106dfSjm199354 } 138911106dfSjm199354 139911106dfSjm199354 140911106dfSjm199354 /* 141911106dfSjm199354 * vs_stats_door_call 142911106dfSjm199354 */ 143911106dfSjm199354 /* ARGSUSED */ 144911106dfSjm199354 static void 145911106dfSjm199354 vs_stats_door_call(void *cookie, char *ptr, size_t size, door_desc_t *dp, 146911106dfSjm199354 uint_t n_desc) 147911106dfSjm199354 { 148*bfc848c6Sjm199354 /* LINTED E_BAD_PTR_CAST_ALIGN */ 149911106dfSjm199354 vs_stats_req_t *req = (vs_stats_req_t *)ptr; 150*bfc848c6Sjm199354 vs_stats_rsp_t rsp; 151911106dfSjm199354 152*bfc848c6Sjm199354 if ((cookie != &vs_stats_door_cookie) || 153*bfc848c6Sjm199354 (ptr == NULL) || 154*bfc848c6Sjm199354 (size != sizeof (vs_stats_req_t)) || 155*bfc848c6Sjm199354 (req->vsr_magic != VS_STATS_DOOR_MAGIC)) { 156*bfc848c6Sjm199354 return; 157*bfc848c6Sjm199354 } 158*bfc848c6Sjm199354 159*bfc848c6Sjm199354 rsp.vsr_magic = VS_STATS_DOOR_MAGIC; 160*bfc848c6Sjm199354 161*bfc848c6Sjm199354 switch (req->vsr_id) { 162911106dfSjm199354 case VS_STATS_GET: 163911106dfSjm199354 (void) pthread_mutex_lock(&vs_stats_mutex); 164*bfc848c6Sjm199354 rsp.vsr_stats = vscan_stats; 165911106dfSjm199354 (void) pthread_mutex_unlock(&vs_stats_mutex); 166*bfc848c6Sjm199354 (void) door_return((char *)&rsp, sizeof (vs_stats_rsp_t), 167*bfc848c6Sjm199354 NULL, 0); 168911106dfSjm199354 break; 169911106dfSjm199354 170911106dfSjm199354 case VS_STATS_RESET: 171*bfc848c6Sjm199354 vs_stats_reset(); 172911106dfSjm199354 (void) door_return(NULL, 0, NULL, 0); 173911106dfSjm199354 break; 174911106dfSjm199354 175911106dfSjm199354 default: 176*bfc848c6Sjm199354 return; 177911106dfSjm199354 } 178911106dfSjm199354 } 179911106dfSjm199354 180911106dfSjm199354 181911106dfSjm199354 /* 182*bfc848c6Sjm199354 * vs_stats_reset 183*bfc848c6Sjm199354 * 184*bfc848c6Sjm199354 * Reset totals and per-engine statistics to 0 185*bfc848c6Sjm199354 */ 186*bfc848c6Sjm199354 static void 187*bfc848c6Sjm199354 vs_stats_reset() 188*bfc848c6Sjm199354 { 189*bfc848c6Sjm199354 int i; 190*bfc848c6Sjm199354 191*bfc848c6Sjm199354 if (vs_stats_check_auth() != 0) 192*bfc848c6Sjm199354 return; 193*bfc848c6Sjm199354 194*bfc848c6Sjm199354 (void) pthread_mutex_lock(&vs_stats_mutex); 195*bfc848c6Sjm199354 196*bfc848c6Sjm199354 vscan_stats.vss_scanned = 0; 197*bfc848c6Sjm199354 vscan_stats.vss_infected = 0; 198*bfc848c6Sjm199354 vscan_stats.vss_cleaned = 0; 199*bfc848c6Sjm199354 vscan_stats.vss_failed = 0; 200*bfc848c6Sjm199354 201*bfc848c6Sjm199354 for (i = 0; i < VS_SE_MAX; i++) 202*bfc848c6Sjm199354 vscan_stats.vss_eng[i].vss_errors = 0; 203*bfc848c6Sjm199354 204*bfc848c6Sjm199354 (void) pthread_mutex_unlock(&vs_stats_mutex); 205*bfc848c6Sjm199354 } 206*bfc848c6Sjm199354 207*bfc848c6Sjm199354 208*bfc848c6Sjm199354 /* 209911106dfSjm199354 * vs_stats_set 210911106dfSjm199354 * 211911106dfSjm199354 * Update scan request stats 212911106dfSjm199354 */ 213911106dfSjm199354 void 214911106dfSjm199354 vs_stats_set(int retval) 215911106dfSjm199354 { 216911106dfSjm199354 (void) pthread_mutex_lock(&vs_stats_mutex); 217911106dfSjm199354 218911106dfSjm199354 switch (retval) { 219911106dfSjm199354 case VS_RESULT_CLEAN: 220911106dfSjm199354 vscan_stats.vss_scanned++; 221911106dfSjm199354 break; 222911106dfSjm199354 case VS_RESULT_CLEANED: 223911106dfSjm199354 vscan_stats.vss_scanned++; 224911106dfSjm199354 vscan_stats.vss_infected++; 225911106dfSjm199354 vscan_stats.vss_cleaned++; 226911106dfSjm199354 break; 227911106dfSjm199354 case VS_RESULT_FORBIDDEN: 228911106dfSjm199354 vscan_stats.vss_scanned++; 229911106dfSjm199354 vscan_stats.vss_infected++; 230911106dfSjm199354 break; 231911106dfSjm199354 case VS_RESULT_SE_ERROR: 232911106dfSjm199354 case VS_RESULT_ERROR: 233911106dfSjm199354 default: 234911106dfSjm199354 vscan_stats.vss_failed++; 235911106dfSjm199354 break; 236911106dfSjm199354 } 237911106dfSjm199354 238911106dfSjm199354 (void) pthread_mutex_unlock(&vs_stats_mutex); 239911106dfSjm199354 } 240911106dfSjm199354 241911106dfSjm199354 242911106dfSjm199354 /* 243911106dfSjm199354 * vs_stats_eng_err 244911106dfSjm199354 * 245911106dfSjm199354 * Increment the error count stat for eng 246911106dfSjm199354 */ 247911106dfSjm199354 void 248911106dfSjm199354 vs_stats_eng_err(char *engid) 249911106dfSjm199354 { 250911106dfSjm199354 int i; 251911106dfSjm199354 252911106dfSjm199354 (void) pthread_mutex_lock(&vs_stats_mutex); 253911106dfSjm199354 254911106dfSjm199354 for (i = 0; i < VS_SE_MAX; i++) { 255911106dfSjm199354 if (*(vscan_stats.vss_eng[i].vss_engid) == 0) 256911106dfSjm199354 break; 257911106dfSjm199354 258911106dfSjm199354 if (strcmp(vscan_stats.vss_eng[i].vss_engid, engid) == 0) { 259911106dfSjm199354 ++(vscan_stats.vss_eng[i].vss_errors); 260911106dfSjm199354 break; 261911106dfSjm199354 } 262911106dfSjm199354 } 263911106dfSjm199354 264911106dfSjm199354 (void) pthread_mutex_unlock(&vs_stats_mutex); 265911106dfSjm199354 } 266911106dfSjm199354 267911106dfSjm199354 268911106dfSjm199354 /* 269911106dfSjm199354 * vs_stats_config 270911106dfSjm199354 */ 271911106dfSjm199354 void 272911106dfSjm199354 vs_stats_config(vs_props_all_t *config) 273911106dfSjm199354 { 274911106dfSjm199354 int i, j; 275911106dfSjm199354 char *engid, *previd; 276911106dfSjm199354 vs_stats_t prev; 277911106dfSjm199354 278911106dfSjm199354 (void) pthread_mutex_lock(&vs_stats_mutex); 279911106dfSjm199354 280911106dfSjm199354 (void) memcpy(&prev, &vscan_stats, sizeof (vs_stats_t)); 281911106dfSjm199354 (void) memset(&vscan_stats.vss_eng, 0, sizeof (vscan_stats.vss_eng)); 282911106dfSjm199354 283911106dfSjm199354 for (i = 0; i < VS_SE_MAX; i++) { 284911106dfSjm199354 engid = config->va_se[i].vep_engid; 285911106dfSjm199354 if (*engid == 0) 286911106dfSjm199354 break; 287911106dfSjm199354 288911106dfSjm199354 (void) strlcpy(vscan_stats.vss_eng[i].vss_engid, engid, 289911106dfSjm199354 VS_SE_NAME_LEN); 290911106dfSjm199354 291911106dfSjm199354 /* find previous error count for engid */ 292911106dfSjm199354 for (j = 0; j < VS_SE_MAX; j++) { 293911106dfSjm199354 previd = prev.vss_eng[j].vss_engid; 294911106dfSjm199354 if (strcmp(previd, engid) == 0) { 295911106dfSjm199354 vscan_stats.vss_eng[i].vss_errors = 296911106dfSjm199354 prev.vss_eng[j].vss_errors; 297911106dfSjm199354 break; 298911106dfSjm199354 } 299911106dfSjm199354 } 300911106dfSjm199354 } 301911106dfSjm199354 302911106dfSjm199354 (void) pthread_mutex_unlock(&vs_stats_mutex); 303911106dfSjm199354 } 304