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 /* 27 * Implementation of the vscan statistics interface 28 */ 29 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <unistd.h> 33 #include <string.h> 34 #include <syslog.h> 35 #include <pthread.h> 36 #include <door.h> 37 #include <pwd.h> 38 #include <auth_attr.h> 39 #include <secdb.h> 40 #include <sys/stat.h> 41 #include <fcntl.h> 42 #include "vs_incl.h" 43 44 45 /* local data */ 46 static vs_stats_t vscan_stats; 47 static int vs_stats_door_cookie; 48 static int vs_stats_door_fd = -1; 49 static pthread_mutex_t vs_stats_mutex = PTHREAD_MUTEX_INITIALIZER; 50 51 52 /* function prototype */ 53 static int vs_stats_check_auth(void); 54 static void vs_stats_reset(void); 55 static void vs_stats_door_call(void *, char *, size_t, door_desc_t *, uint_t); 56 57 58 /* 59 * vs_stats_init 60 * 61 * Invoked on daemon load and unload 62 */ 63 int 64 vs_stats_init(void) 65 { 66 (void) pthread_mutex_lock(&vs_stats_mutex); 67 68 (void) memset(&vscan_stats, 0, sizeof (vs_stats_t)); 69 70 /* door initialization */ 71 if ((vs_stats_door_fd = door_create(vs_stats_door_call, 72 &vs_stats_door_cookie, (DOOR_UNREF | DOOR_REFUSE_DESC))) < 0) { 73 vs_stats_door_fd = -1; 74 } else { 75 (void) fdetach(VS_STATS_DOOR_NAME); 76 if (fattach(vs_stats_door_fd, VS_STATS_DOOR_NAME) < 0) { 77 (void) door_revoke(vs_stats_door_fd); 78 vs_stats_door_fd = -1; 79 } 80 } 81 82 (void) pthread_mutex_unlock(&vs_stats_mutex); 83 84 return ((vs_stats_door_fd == -1) ? -1 : 0); 85 } 86 87 88 /* 89 * vs_stats_fini 90 * 91 * Invoked on daemon unload 92 */ 93 void 94 vs_stats_fini(void) 95 { 96 (void) pthread_mutex_lock(&vs_stats_mutex); 97 98 /* door termination */ 99 if (vs_stats_door_fd != -1) 100 (void) door_revoke(vs_stats_door_fd); 101 vs_stats_door_fd = -1; 102 103 (void) fdetach(VS_STATS_DOOR_NAME); 104 (void) unlink(VS_STATS_DOOR_NAME); 105 106 (void) pthread_mutex_unlock(&vs_stats_mutex); 107 } 108 109 110 /* 111 * vs_stats_check_auth 112 * 113 * Returns: 0 caller authorized to reset stats 114 * -1 caller not authorized to reset stats 115 */ 116 static int 117 vs_stats_check_auth() 118 { 119 ucred_t *uc = NULL; 120 uid_t uid; 121 struct passwd *pw; 122 123 if (door_ucred(&uc) != 0) 124 return (-1); 125 126 if (((uid = ucred_getsuid(uc)) == (uid_t)-1) || 127 ((pw = getpwuid(uid)) == NULL) || 128 (chkauthattr(VS_VALUE_AUTH, pw->pw_name) != 1)) { 129 ucred_free(uc); 130 return (-1); 131 } 132 133 ucred_free(uc); 134 return (0); 135 } 136 137 138 /* 139 * vs_stats_door_call 140 */ 141 /* ARGSUSED */ 142 static void 143 vs_stats_door_call(void *cookie, char *ptr, size_t size, door_desc_t *dp, 144 uint_t n_desc) 145 { 146 /* LINTED E_BAD_PTR_CAST_ALIGN */ 147 vs_stats_req_t *req = (vs_stats_req_t *)ptr; 148 vs_stats_rsp_t rsp; 149 150 if ((cookie != &vs_stats_door_cookie) || 151 (ptr == NULL) || 152 (size != sizeof (vs_stats_req_t)) || 153 (req->vsr_magic != VS_STATS_DOOR_MAGIC)) { 154 return; 155 } 156 157 rsp.vsr_magic = VS_STATS_DOOR_MAGIC; 158 159 switch (req->vsr_id) { 160 case VS_STATS_GET: 161 (void) pthread_mutex_lock(&vs_stats_mutex); 162 rsp.vsr_stats = vscan_stats; 163 (void) pthread_mutex_unlock(&vs_stats_mutex); 164 (void) door_return((char *)&rsp, sizeof (vs_stats_rsp_t), 165 NULL, 0); 166 break; 167 168 case VS_STATS_RESET: 169 vs_stats_reset(); 170 (void) door_return(NULL, 0, NULL, 0); 171 break; 172 173 default: 174 return; 175 } 176 } 177 178 179 /* 180 * vs_stats_reset 181 * 182 * Reset totals and per-engine statistics to 0 183 */ 184 static void 185 vs_stats_reset() 186 { 187 int i; 188 189 if (vs_stats_check_auth() != 0) 190 return; 191 192 (void) pthread_mutex_lock(&vs_stats_mutex); 193 194 vscan_stats.vss_scanned = 0; 195 vscan_stats.vss_infected = 0; 196 vscan_stats.vss_cleaned = 0; 197 vscan_stats.vss_failed = 0; 198 199 for (i = 0; i < VS_SE_MAX; i++) 200 vscan_stats.vss_eng[i].vss_errors = 0; 201 202 (void) pthread_mutex_unlock(&vs_stats_mutex); 203 } 204 205 206 /* 207 * vs_stats_set 208 * 209 * Update scan request stats 210 */ 211 void 212 vs_stats_set(int retval) 213 { 214 (void) pthread_mutex_lock(&vs_stats_mutex); 215 216 switch (retval) { 217 case VS_RESULT_CLEAN: 218 vscan_stats.vss_scanned++; 219 break; 220 case VS_RESULT_CLEANED: 221 vscan_stats.vss_scanned++; 222 vscan_stats.vss_infected++; 223 vscan_stats.vss_cleaned++; 224 break; 225 case VS_RESULT_FORBIDDEN: 226 vscan_stats.vss_scanned++; 227 vscan_stats.vss_infected++; 228 break; 229 case VS_RESULT_SE_ERROR: 230 case VS_RESULT_ERROR: 231 default: 232 vscan_stats.vss_failed++; 233 break; 234 } 235 236 (void) pthread_mutex_unlock(&vs_stats_mutex); 237 } 238 239 240 /* 241 * vs_stats_eng_err 242 * 243 * Increment the error count stat for eng 244 */ 245 void 246 vs_stats_eng_err(char *engid) 247 { 248 int i; 249 250 (void) pthread_mutex_lock(&vs_stats_mutex); 251 252 for (i = 0; i < VS_SE_MAX; i++) { 253 if (*(vscan_stats.vss_eng[i].vss_engid) == 0) 254 break; 255 256 if (strcmp(vscan_stats.vss_eng[i].vss_engid, engid) == 0) { 257 ++(vscan_stats.vss_eng[i].vss_errors); 258 break; 259 } 260 } 261 262 (void) pthread_mutex_unlock(&vs_stats_mutex); 263 } 264 265 266 /* 267 * vs_stats_config 268 */ 269 void 270 vs_stats_config(vs_props_all_t *config) 271 { 272 int i, j; 273 char *engid, *previd; 274 vs_stats_t prev; 275 276 (void) pthread_mutex_lock(&vs_stats_mutex); 277 278 (void) memcpy(&prev, &vscan_stats, sizeof (vs_stats_t)); 279 (void) memset(&vscan_stats.vss_eng, 0, sizeof (vscan_stats.vss_eng)); 280 281 for (i = 0; i < VS_SE_MAX; i++) { 282 engid = config->va_se[i].vep_engid; 283 if (*engid == 0) 284 break; 285 286 (void) strlcpy(vscan_stats.vss_eng[i].vss_engid, engid, 287 VS_SE_NAME_LEN); 288 289 /* find previous error count for engid */ 290 for (j = 0; j < VS_SE_MAX; j++) { 291 previd = prev.vss_eng[j].vss_engid; 292 if (strcmp(previd, engid) == 0) { 293 vscan_stats.vss_eng[i].vss_errors = 294 prev.vss_eng[j].vss_errors; 295 break; 296 } 297 } 298 } 299 300 (void) pthread_mutex_unlock(&vs_stats_mutex); 301 } 302