xref: /illumos-gate/usr/src/cmd/vscan/vscand/vs_stats.c (revision 3d393ee6c37fa10ac512ed6d36109ad616dc7c1a)
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