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