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
vs_stats_init(void)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
vs_stats_fini(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
vs_stats_check_auth()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
vs_stats_door_call(void * cookie,char * ptr,size_t size,door_desc_t * dp,uint_t n_desc)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
vs_stats_reset()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
vs_stats_set(int retval)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
vs_stats_eng_err(char * engid)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
vs_stats_config(vs_props_all_t * config)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