1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * Implementation of the vscan statistics interface 30 */ 31 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <unistd.h> 35 #include <string.h> 36 #include <syslog.h> 37 #include <pthread.h> 38 #include <door.h> 39 #include <pwd.h> 40 #include <auth_attr.h> 41 #include <secdb.h> 42 #include <sys/stat.h> 43 #include <fcntl.h> 44 #include "vs_incl.h" 45 46 47 /* local data */ 48 static vs_stats_t vscan_stats; 49 static int vs_stats_door_cookie; 50 static int vs_stats_door_fd = -1; 51 static pthread_mutex_t vs_stats_mutex = PTHREAD_MUTEX_INITIALIZER; 52 53 54 /* function prototype */ 55 static int vs_stats_check_auth(void); 56 static void vs_stats_reset(void); 57 static void vs_stats_door_call(void *, char *, size_t, door_desc_t *, uint_t); 58 59 60 /* 61 * vs_stats_init 62 * 63 * Invoked on daemon load and unload 64 */ 65 int 66 vs_stats_init(void) 67 { 68 (void) pthread_mutex_lock(&vs_stats_mutex); 69 70 (void) memset(&vscan_stats, 0, sizeof (vs_stats_t)); 71 72 /* door initialization */ 73 if ((vs_stats_door_fd = door_create(vs_stats_door_call, 74 &vs_stats_door_cookie, (DOOR_UNREF | DOOR_REFUSE_DESC))) < 0) { 75 vs_stats_door_fd = -1; 76 } else { 77 (void) fdetach(VS_STATS_DOOR_NAME); 78 if (fattach(vs_stats_door_fd, VS_STATS_DOOR_NAME) < 0) { 79 (void) door_revoke(vs_stats_door_fd); 80 vs_stats_door_fd = -1; 81 } 82 } 83 84 (void) pthread_mutex_unlock(&vs_stats_mutex); 85 86 return ((vs_stats_door_fd == -1) ? -1 : 0); 87 } 88 89 90 /* 91 * vs_stats_fini 92 * 93 * Invoked on daemon unload 94 */ 95 void 96 vs_stats_fini(void) 97 { 98 (void) pthread_mutex_lock(&vs_stats_mutex); 99 100 /* door termination */ 101 if (vs_stats_door_fd != -1) 102 (void) door_revoke(vs_stats_door_fd); 103 vs_stats_door_fd = -1; 104 105 (void) fdetach(VS_STATS_DOOR_NAME); 106 (void) unlink(VS_STATS_DOOR_NAME); 107 108 (void) pthread_mutex_unlock(&vs_stats_mutex); 109 } 110 111 112 /* 113 * vs_stats_check_auth 114 * 115 * Returns: 0 caller authorized to reset stats 116 * -1 caller not authorized to reset stats 117 */ 118 static int 119 vs_stats_check_auth() 120 { 121 ucred_t *uc = NULL; 122 uid_t uid; 123 struct passwd *pw; 124 125 if (door_ucred(&uc) != 0) 126 return (-1); 127 128 if (((uid = ucred_getsuid(uc)) == (uid_t)-1) || 129 ((pw = getpwuid(uid)) == NULL) || 130 (chkauthattr(VS_VALUE_AUTH, pw->pw_name) != 1)) { 131 ucred_free(uc); 132 return (-1); 133 } 134 135 ucred_free(uc); 136 return (0); 137 } 138 139 140 /* 141 * vs_stats_door_call 142 */ 143 /* ARGSUSED */ 144 static void 145 vs_stats_door_call(void *cookie, char *ptr, size_t size, door_desc_t *dp, 146 uint_t n_desc) 147 { 148 /* LINTED E_BAD_PTR_CAST_ALIGN */ 149 vs_stats_req_t *req = (vs_stats_req_t *)ptr; 150 vs_stats_rsp_t rsp; 151 152 if ((cookie != &vs_stats_door_cookie) || 153 (ptr == NULL) || 154 (size != sizeof (vs_stats_req_t)) || 155 (req->vsr_magic != VS_STATS_DOOR_MAGIC)) { 156 return; 157 } 158 159 rsp.vsr_magic = VS_STATS_DOOR_MAGIC; 160 161 switch (req->vsr_id) { 162 case VS_STATS_GET: 163 (void) pthread_mutex_lock(&vs_stats_mutex); 164 rsp.vsr_stats = vscan_stats; 165 (void) pthread_mutex_unlock(&vs_stats_mutex); 166 (void) door_return((char *)&rsp, sizeof (vs_stats_rsp_t), 167 NULL, 0); 168 break; 169 170 case VS_STATS_RESET: 171 vs_stats_reset(); 172 (void) door_return(NULL, 0, NULL, 0); 173 break; 174 175 default: 176 return; 177 } 178 } 179 180 181 /* 182 * vs_stats_reset 183 * 184 * Reset totals and per-engine statistics to 0 185 */ 186 static void 187 vs_stats_reset() 188 { 189 int i; 190 191 if (vs_stats_check_auth() != 0) 192 return; 193 194 (void) pthread_mutex_lock(&vs_stats_mutex); 195 196 vscan_stats.vss_scanned = 0; 197 vscan_stats.vss_infected = 0; 198 vscan_stats.vss_cleaned = 0; 199 vscan_stats.vss_failed = 0; 200 201 for (i = 0; i < VS_SE_MAX; i++) 202 vscan_stats.vss_eng[i].vss_errors = 0; 203 204 (void) pthread_mutex_unlock(&vs_stats_mutex); 205 } 206 207 208 /* 209 * vs_stats_set 210 * 211 * Update scan request stats 212 */ 213 void 214 vs_stats_set(int retval) 215 { 216 (void) pthread_mutex_lock(&vs_stats_mutex); 217 218 switch (retval) { 219 case VS_RESULT_CLEAN: 220 vscan_stats.vss_scanned++; 221 break; 222 case VS_RESULT_CLEANED: 223 vscan_stats.vss_scanned++; 224 vscan_stats.vss_infected++; 225 vscan_stats.vss_cleaned++; 226 break; 227 case VS_RESULT_FORBIDDEN: 228 vscan_stats.vss_scanned++; 229 vscan_stats.vss_infected++; 230 break; 231 case VS_RESULT_SE_ERROR: 232 case VS_RESULT_ERROR: 233 default: 234 vscan_stats.vss_failed++; 235 break; 236 } 237 238 (void) pthread_mutex_unlock(&vs_stats_mutex); 239 } 240 241 242 /* 243 * vs_stats_eng_err 244 * 245 * Increment the error count stat for eng 246 */ 247 void 248 vs_stats_eng_err(char *engid) 249 { 250 int i; 251 252 (void) pthread_mutex_lock(&vs_stats_mutex); 253 254 for (i = 0; i < VS_SE_MAX; i++) { 255 if (*(vscan_stats.vss_eng[i].vss_engid) == 0) 256 break; 257 258 if (strcmp(vscan_stats.vss_eng[i].vss_engid, engid) == 0) { 259 ++(vscan_stats.vss_eng[i].vss_errors); 260 break; 261 } 262 } 263 264 (void) pthread_mutex_unlock(&vs_stats_mutex); 265 } 266 267 268 /* 269 * vs_stats_config 270 */ 271 void 272 vs_stats_config(vs_props_all_t *config) 273 { 274 int i, j; 275 char *engid, *previd; 276 vs_stats_t prev; 277 278 (void) pthread_mutex_lock(&vs_stats_mutex); 279 280 (void) memcpy(&prev, &vscan_stats, sizeof (vs_stats_t)); 281 (void) memset(&vscan_stats.vss_eng, 0, sizeof (vscan_stats.vss_eng)); 282 283 for (i = 0; i < VS_SE_MAX; i++) { 284 engid = config->va_se[i].vep_engid; 285 if (*engid == 0) 286 break; 287 288 (void) strlcpy(vscan_stats.vss_eng[i].vss_engid, engid, 289 VS_SE_NAME_LEN); 290 291 /* find previous error count for engid */ 292 for (j = 0; j < VS_SE_MAX; j++) { 293 previd = prev.vss_eng[j].vss_engid; 294 if (strcmp(previd, engid) == 0) { 295 vscan_stats.vss_eng[i].vss_errors = 296 prev.vss_eng[j].vss_errors; 297 break; 298 } 299 } 300 } 301 302 (void) pthread_mutex_unlock(&vs_stats_mutex); 303 } 304