xref: /illumos-gate/usr/src/cmd/vscan/vscand/vs_stats.c (revision 2a8bcb4e)
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
vs_stats_init(void)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
vs_stats_fini(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
vs_stats_check_auth()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
vs_stats_door_call(void * cookie,char * ptr,size_t size,door_desc_t * dp,uint_t n_desc)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
vs_stats_reset()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
vs_stats_set(int retval)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
vs_stats_eng_err(char * engid)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
vs_stats_config(vs_props_all_t * config)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