xref: /illumos-gate/usr/src/cmd/vscan/vscand/vs_main.c (revision 628e3cbed6489fa1db545d8524a06cd6535af456)
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  * vscand Daemon Program
30  */
31 
32 #include <stdio.h>
33 #include <sys/stat.h>
34 #include <sys/filio.h>
35 #include <sys/types.h>
36 #include <sys/socket.h>
37 #include <sys/ioctl.h>
38 #include <sys/param.h>
39 #include <zone.h>
40 #include <tsol/label.h>
41 #include <string.h>
42 #include <stdlib.h>
43 #include <fcntl.h>
44 #include <wait.h>
45 #include <unistd.h>
46 #include <getopt.h>
47 #include <stdarg.h>
48 #include <libscf.h>
49 #include <signal.h>
50 #include <libintl.h>
51 #include <netinet/in.h>
52 #include <arpa/inet.h>
53 #include <ctype.h>
54 #include <pthread.h>
55 #include <syslog.h>
56 #include <locale.h>
57 #include <pwd.h>
58 #include <grp.h>
59 #include <priv_utils.h>
60 #include <rctl.h>
61 #include "vs_incl.h"
62 
63 #define	VS_FILE_DESCRIPTORS	512
64 
65 static int vscand_fg = 0; /* daemon by default */
66 static vs_daemon_state_t vscand_state = VS_STATE_INIT;
67 static int vscand_sigval = 0;
68 static int vscand_kdrv_fd = -1;
69 static pthread_mutex_t vscand_cfg_mutex = PTHREAD_MUTEX_INITIALIZER;
70 static pthread_cond_t vscand_cfg_cv;
71 static pthread_t vscand_cfg_tid = 0;
72 
73 /* virus log path */
74 static char vscand_vlog[MAXPATHLEN];
75 
76 /* user and group ids - default to 0 */
77 static uid_t root_uid = 0, daemon_uid = 0;
78 static gid_t sys_gid = 0;
79 
80 
81 /* local function prototypes */
82 static void vscand_sig_handler(int);
83 static int vscand_parse_args(int, char **);
84 static void vscand_get_uid_gid();
85 static int vscand_init_file(char *, uid_t, gid_t, mode_t);
86 static void vscand_usage(char *);
87 static int vscand_daemonize_init(void);
88 static void vscand_daemonize_fini(int, int);
89 static int vscand_init(void);
90 static void vscand_fini(void);
91 static int vscand_cfg_init(void);
92 static void vscand_cfg_fini(void);
93 static void *vscand_cfg_handler(void *);
94 static int vscand_configure(void);
95 static void vscand_dtrace_cfg(vs_props_all_t *);
96 static int vscand_kernel_bind(void);
97 static void vscand_kernel_unbind(void);
98 static int vscand_kernel_enable(int);
99 static void vscand_kernel_disable(void);
100 static int vscand_kernel_config(vs_config_t *);
101 static int vscand_kernel_max_req(uint32_t *);
102 static void vscand_error(const char *);
103 static int vscand_get_viruslog(void);
104 static int vscand_set_resource_limits(void);
105 
106 
107 /*
108  * Enable libumem debugging by default on DEBUG builds.
109  */
110 #ifdef DEBUG
111 const char *
112 _umem_debug_init(void)
113 {
114 	return ("default,verbose"); /* $UMEM_DEBUG setting */
115 }
116 
117 const char *
118 _umem_logging_init(void)
119 {
120 	return ("fail,contents"); /* $UMEM_LOGGING setting */
121 }
122 #endif
123 
124 
125 /*
126  * vs_sig_handler
127  */
128 static void
129 vscand_sig_handler(int sig)
130 {
131 	if (vscand_sigval == 0)
132 		vscand_sigval = sig;
133 }
134 
135 
136 /*
137  * main
138  *
139  * main must return SMF return code (see smf_method (5)) if vscand
140  * is invoked directly by smf (see manifest: vscan.xml)
141  * Exit codes: SMF_EXIT_ERR_CONFIG - error
142  *             SMF_EXIT_ERR_FATAL - fatal error
143  *             SMF_EXIT_OK - success
144  */
145 int
146 main(int argc, char **argv)
147 {
148 	int err_stat = 0, pfd = -1;
149 	sigset_t set;
150 	struct sigaction act;
151 	int sigval;
152 
153 	mode_t log_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
154 	mode_t door_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
155 
156 	(void) setlocale(LC_ALL, "");
157 	openlog("vscand", 0, LOG_DAEMON);
158 
159 	/* check if running in global zone; other zones not supported */
160 	if (getzoneid() != GLOBAL_ZONEID) {
161 		vscand_error(gettext("non-global zone not supported"));
162 		exit(SMF_EXIT_ERR_FATAL);
163 	}
164 
165 	/* check for a Trusted Solaris environment; not supported */
166 	if (is_system_labeled()) {
167 		vscand_error(gettext("Trusted Extensions not supported"));
168 		exit(SMF_EXIT_ERR_FATAL);
169 	}
170 
171 	/* Parse arguments */
172 	if (vscand_parse_args(argc, argv) != 0)
173 		exit(SMF_EXIT_ERR_CONFIG);
174 
175 	vscand_get_uid_gid();
176 
177 	/*
178 	 * Initializetion of virus log and statistic door file
179 	 * MUST be done BEFORE vscand_daemonize_init resets uid/gid.
180 	 * Only root can create the files in /var/log and /var/run.
181 	 */
182 	if ((vscand_get_viruslog() != 0) ||
183 	    (vscand_vlog[0] == '\0') ||
184 	    (vscand_init_file(vscand_vlog, root_uid, sys_gid, log_mode) != 0)) {
185 		*vscand_vlog = 0;
186 	}
187 
188 	(void) vscand_init_file(VS_STATS_DOOR_NAME,
189 	    daemon_uid, sys_gid, door_mode);
190 
191 	/*
192 	 * Once we're done setting our global state up, set up signal handlers
193 	 * for ensuring orderly termination on SIGTERM.
194 	 */
195 	(void) sigfillset(&set);
196 	(void) sigdelset(&set, SIGABRT); /* always unblocked for ASSERT() */
197 
198 	(void) sigfillset(&act.sa_mask);
199 	act.sa_handler = vscand_sig_handler;
200 	act.sa_flags = 0;
201 
202 	(void) sigaction(SIGTERM, &act, NULL);
203 	(void) sigaction(SIGHUP, &act, NULL); /* Refresh config */
204 	(void) sigaction(SIGINT, &act, NULL);
205 	(void) sigaction(SIGPIPE, &act, NULL);
206 	(void) sigdelset(&set, SIGTERM);
207 	(void) sigdelset(&set, SIGHUP);
208 	(void) sigdelset(&set, SIGINT);
209 	(void) sigdelset(&set, SIGPIPE);
210 
211 	if (vscand_fg) {
212 		(void) sigdelset(&set, SIGTSTP);
213 		(void) sigdelset(&set, SIGTTIN);
214 		(void) sigdelset(&set, SIGTTOU);
215 
216 		if (vscand_init() != 0) {
217 			vscand_error(gettext("failed to initialize service"));
218 			exit(SMF_EXIT_ERR_CONFIG);
219 		}
220 	} else {
221 		/*
222 		 * "pfd" is a pipe descriptor -- any fatal errors
223 		 * during subsequent initialization of the child
224 		 * process should be written to this pipe and the
225 		 * parent will report this error as the exit status.
226 		 */
227 		pfd = vscand_daemonize_init();
228 
229 		if (vscand_init() != 0) {
230 			vscand_error(gettext("failed to initialize service"));
231 			exit(SMF_EXIT_ERR_CONFIG);
232 		}
233 
234 		vscand_daemonize_fini(pfd, err_stat);
235 	}
236 
237 	vscand_state = VS_STATE_RUNNING;
238 
239 	/* Wait here until shutdown */
240 	while (vscand_state == VS_STATE_RUNNING) {
241 		if (vscand_sigval == 0)
242 			(void) sigsuspend(&set);
243 
244 		sigval = vscand_sigval;
245 		vscand_sigval = 0;
246 
247 		switch (sigval) {
248 		case 0:
249 		case SIGPIPE:
250 			break;
251 		case SIGHUP:
252 			(void) pthread_cond_signal(&vscand_cfg_cv);
253 			break;
254 		default:
255 			vscand_state = VS_STATE_SHUTDOWN;
256 			break;
257 		}
258 	}
259 
260 	vscand_fini();
261 	return (SMF_EXIT_OK);
262 }
263 
264 
265 /*
266  * vscand_parse_args
267  * Routine to parse the arguments to the daemon program
268  * 'f' argument runs process in the foreground instead of as a daemon
269  */
270 int
271 vscand_parse_args(int argc, char **argv)
272 {
273 	int	optchar;
274 
275 	while ((optchar = getopt(argc, argv, "f?")) != EOF) {
276 		switch (optchar) {
277 		case 'f':
278 			vscand_fg = 1;
279 			break;
280 		default:
281 			vscand_usage(argv[0]);
282 			return (-1);
283 		}
284 	}
285 	return (0);
286 }
287 
288 
289 /*
290  * vscand_usage
291  */
292 static void
293 vscand_usage(char *progname)
294 {
295 	char buf[128];
296 
297 	(void) snprintf(buf, sizeof (buf), "%s %s [-f]",
298 	    gettext("Usage"), progname);
299 	vscand_error(buf);
300 
301 	(void) snprintf(buf, sizeof (buf), "\t-f %s\n",
302 	    gettext("run program in foreground"));
303 	vscand_error(buf);
304 }
305 
306 
307 /*
308  * vscand_get_uid_gid
309  *
310  * failure to access a uid/gid results in the default (0) being used.
311  */
312 static void
313 vscand_get_uid_gid()
314 {
315 	struct passwd *pwd;
316 	struct group *grp;
317 
318 	if ((pwd = getpwnam("root")) != NULL)
319 		root_uid = pwd->pw_uid;
320 
321 	if ((pwd = getpwnam("daemon")) != NULL)
322 		daemon_uid = pwd->pw_uid;
323 
324 	if ((grp = getgrnam("sys")) != NULL)
325 		sys_gid = grp->gr_gid;
326 }
327 
328 
329 /*
330  * vscand_daemonize_init
331  *
332  * This function will fork off a child process, from which
333  * only the child will return.
334  */
335 static int
336 vscand_daemonize_init(void)
337 {
338 	int status, pfds[2];
339 	sigset_t set, oset;
340 	pid_t pid;
341 
342 	/*
343 	 * Reset process owner/group to daemon/sys. Root ownership is only
344 	 * required to initialize virus log file in /var/log
345 	 */
346 	if (__init_daemon_priv(PU_RESETGROUPS | PU_LIMITPRIVS,
347 	    daemon_uid, sys_gid,
348 	    PRIV_PROC_AUDIT, PRIV_FILE_DAC_SEARCH, PRIV_FILE_DAC_READ,
349 	    PRIV_FILE_FLAG_SET, NULL) != 0) {
350 		vscand_error(gettext("failed to initialize privileges"));
351 		_exit(SMF_EXIT_ERR_FATAL);
352 	}
353 
354 	/*
355 	 * Block all signals prior to the fork and leave them blocked in the
356 	 * parent so we don't get in a situation where the parent gets SIGINT
357 	 * and returns non-zero exit status and the child is actually running.
358 	 * In the child, restore the signal mask once we've done our setsid().
359 	 */
360 	(void) sigfillset(&set);
361 	(void) sigdelset(&set, SIGABRT);
362 	(void) sigprocmask(SIG_BLOCK, &set, &oset);
363 
364 	if (pipe(pfds) == -1) {
365 		vscand_error(gettext("failed to create pipe for daemonize"));
366 		_exit(SMF_EXIT_ERR_FATAL);
367 	}
368 
369 	if ((pid = fork()) == -1) {
370 		vscand_error(gettext("failed to fork for daemonize"));
371 		_exit(SMF_EXIT_ERR_FATAL);
372 	}
373 
374 	/*
375 	 * If we're the parent process, wait for either the child to send us
376 	 * the appropriate exit status over the pipe or for the read to fail
377 	 * (presumably with 0 for EOF if our child terminated abnormally).
378 	 * If the read fails, exit with either the child's exit status if it
379 	 * exited or with SMF_EXIT_ERR_FATAL if it died from a fatal signal.
380 	 */
381 	if (pid != 0) {
382 		(void) close(pfds[1]);
383 
384 		if (read(pfds[0], &status, sizeof (status)) == sizeof (status))
385 			_exit(status);
386 
387 		if (waitpid(pid, &status, 0) == pid && WIFEXITED(status))
388 			_exit(WEXITSTATUS(status));
389 
390 		vscand_error(gettext("failed to daemonize"));
391 		_exit(SMF_EXIT_ERR_FATAL);
392 	}
393 
394 
395 	(void) setsid();
396 	(void) sigprocmask(SIG_SETMASK, &oset, NULL);
397 	(void) chdir("/");
398 	(void) umask(022);
399 	(void) close(pfds[0]);
400 
401 	return (pfds[1]);
402 }
403 
404 
405 /*
406  * vscand_daemonize_fini
407  * Now that we're running, if a pipe fd was specified, write an exit
408  * status to it to indicate that our parent process can safely detach.
409  */
410 static void
411 vscand_daemonize_fini(int fd, int err_status)
412 {
413 	if (fd >= 0)
414 		(void) write(fd, &err_status, sizeof (err_status));
415 
416 	(void) close(fd);
417 
418 	/* Restore standard file descriptors */
419 	if ((fd = open("/dev/null", O_RDWR)) >= 0) {
420 		(void) fcntl(fd, F_DUP2FD, STDIN_FILENO);
421 		(void) fcntl(fd, F_DUP2FD, STDOUT_FILENO);
422 		(void) fcntl(fd, F_DUP2FD, STDERR_FILENO);
423 		(void) close(fd);
424 	}
425 
426 	/* clear basic privileges not required by vscand */
427 	__fini_daemon_priv(PRIV_PROC_FORK, PRIV_PROC_EXEC, PRIV_PROC_SESSION,
428 	    PRIV_FILE_LINK_ANY, PRIV_PROC_INFO, (char *)NULL);
429 }
430 
431 
432 /*
433  * vscand_init_file
434  *
435  * create specified file and set its uid, gid and mode
436  */
437 static int
438 vscand_init_file(char *filepath, uid_t uid, gid_t gid, mode_t access_mode)
439 {
440 	int fd, rc = 0;
441 	struct stat stat_buf;
442 	char buf[MAXPATHLEN];
443 
444 	if ((fd = open(filepath, O_RDONLY | O_CREAT, access_mode)) == -1) {
445 		rc = -1;
446 	} else {
447 		if (fstat(fd, &stat_buf) != 0) {
448 			rc = -1;
449 		} else {
450 			if ((stat_buf.st_mode & S_IAMB) != access_mode) {
451 				if (fchmod(fd, access_mode) != 0)
452 					rc = -1;
453 			}
454 
455 			if ((stat_buf.st_uid != uid) ||
456 			    (stat_buf.st_gid != gid)) {
457 				if (fchown(fd, uid, gid) != 0)
458 					rc = -1;
459 			}
460 		}
461 
462 		(void) close(fd);
463 	}
464 
465 	if (rc == -1) {
466 		(void) snprintf(buf, MAXPATHLEN, "%s %s",
467 		    gettext("Failed to initialize"), filepath);
468 		vscand_error(buf);
469 	}
470 
471 	return (rc);
472 }
473 
474 
475 /*
476  * vscand_init
477  *
478  * There are some requirements on the order in which the daemon
479  * initialization functions are called.
480  *
481  * - vscand_kernel_bind - bind to kernel module
482  * - vs_eng_init populates vs_icap data and thus vs_icap_init MUST be
483  *   called before vs_eng_init
484  * - vscand_configure - load the configuration
485  * - vs_door_init - start vscan door server
486  * - vscand_kernel_enable - enable scan requests from kernel
487  */
488 static int
489 vscand_init(void)
490 {
491 	int door_fd = -1;
492 	uint32_t max_req;
493 
494 	if (vscand_kernel_bind() < 0)
495 		return (-1);
496 
497 	if (vscand_kernel_max_req(&max_req) == -1)
498 		return (-1);
499 
500 	if (vs_svc_init(max_req) != 0)
501 		return (-1);
502 
503 	if (vs_stats_init() != 0)
504 		vscand_error(
505 		    gettext("failed to initialize statistics interface"));
506 
507 	vs_icap_init();
508 	vs_eng_init();
509 
510 	/* initialize configuration and handler thread */
511 	if (vscand_cfg_init() != 0) {
512 		vscand_error(gettext("failed to initialize configuration"));
513 		vscand_fini();
514 		return (-1);
515 	}
516 
517 	(void) vscand_set_resource_limits();
518 
519 	if (((door_fd = vs_door_init()) < 0) ||
520 	    (vscand_kernel_enable(door_fd) < 0)) {
521 		vscand_fini();
522 		return (-1);
523 	}
524 
525 	return (0);
526 }
527 
528 
529 /*
530  * vscand_fini
531  *
532  * vscand_kernel_disable - should be called first to ensure that no
533  *	more scan requests are initiated from the kernel module
534  * vs_svc_terminate - terminate requests and wait for thread completion
535  * vs_xxx_fini - module cleanup routines
536  * vscand_kernel_unbind - should be called last to tell the kernel module
537  *	that vscand is shutdown.
538  */
539 static void
540 vscand_fini(void)
541 {
542 	vscand_kernel_disable();
543 
544 	/* terminate reconfiguration handler thread */
545 	vscand_cfg_fini();
546 
547 	/* terminate requests and wait for completion */
548 	vs_svc_terminate();
549 
550 	/* clean up */
551 	vs_svc_fini();
552 	vs_eng_fini();
553 	vs_icap_fini();
554 	vs_door_fini();
555 	vs_stats_fini();
556 
557 	vscand_kernel_unbind();
558 }
559 
560 
561 /*
562  * vscand_cfg_init
563  *
564  * initialize configuration and reconfiguration handler thread
565  */
566 static int
567 vscand_cfg_init(void)
568 {
569 	int rc;
570 
571 	(void) pthread_cond_init(&vscand_cfg_cv, NULL);
572 
573 	(void) pthread_mutex_lock(&vscand_cfg_mutex);
574 	rc = vscand_configure();
575 	(void) pthread_mutex_unlock(&vscand_cfg_mutex);
576 
577 	if (rc != 0)
578 		return (-1);
579 
580 	if (pthread_create(&vscand_cfg_tid, NULL, vscand_cfg_handler, 0) != 0) {
581 		vscand_cfg_tid = 0;
582 		return (-1);
583 	}
584 
585 	return (0);
586 }
587 
588 
589 /*
590  * vscand_cfg_fini
591  *
592  * terminate reconfiguration handler thread
593  */
594 static void
595 vscand_cfg_fini()
596 {
597 	if (vscand_cfg_tid != 0) {
598 		(void) pthread_cond_signal(&vscand_cfg_cv);
599 		(void) pthread_join(vscand_cfg_tid, NULL);
600 		vscand_cfg_tid = 0;
601 	}
602 	(void) pthread_cond_destroy(&vscand_cfg_cv);
603 }
604 
605 
606 /*
607  * vscand_cfg_handler
608  * wait for reconfiguration event and reload configuration
609  * exit on VS_STATE_SHUTDOWN
610  */
611 /*ARGSUSED*/
612 static void *
613 vscand_cfg_handler(void *arg)
614 {
615 	(void) pthread_mutex_lock(&vscand_cfg_mutex);
616 
617 	while (pthread_cond_wait(&vscand_cfg_cv, &vscand_cfg_mutex) == 0) {
618 		if (vscand_state == VS_STATE_SHUTDOWN)
619 			break;
620 
621 		(void) vscand_configure();
622 	}
623 
624 	(void) pthread_mutex_unlock(&vscand_cfg_mutex);
625 
626 	return (NULL);
627 }
628 
629 
630 /*
631  * vscand_configure
632  */
633 static int
634 vscand_configure(void)
635 {
636 	uint32_t len;
637 	vs_config_t kconfig;
638 	vs_props_all_t config;
639 
640 	(void) memset(&config, 0, sizeof (vs_props_all_t));
641 	if (vs_props_get_all(&config) != VS_ERR_NONE) {
642 		vscand_error(gettext("configuration data error"));
643 		return (-1);
644 	}
645 
646 	(void) memset(&kconfig, 0, sizeof (vs_config_t));
647 	len = sizeof (kconfig.vsc_types);
648 	if (vs_parse_types(config.va_props.vp_types,
649 	    kconfig.vsc_types, &len) != 0) {
650 		vscand_error(gettext("configuration data error - types"));
651 		return (-1);
652 	}
653 	kconfig.vsc_types_len = len;
654 
655 	/* Convert the maxfsize string from the configuration into bytes */
656 	if (vs_strtonum(config.va_props.vp_maxsize,
657 	    &kconfig.vsc_max_size) != 0) {
658 		vscand_error(gettext("configuration data error - max-size"));
659 		return (-1);
660 	}
661 	kconfig.vsc_allow = config.va_props.vp_maxsize_action ? 1LL : 0LL;
662 
663 	/* Send configuration update to kernel */
664 	if (vscand_kernel_config(&kconfig) != 0) {
665 		return (-1);
666 	}
667 
668 	/* dtrace the configuration data */
669 	vscand_dtrace_cfg(&config);
670 
671 	/* propagate configuration changes */
672 	vs_eng_config(&config);
673 	vs_stats_config(&config);
674 
675 	return (0);
676 }
677 
678 
679 /*
680  * vscand_get_state
681  */
682 vs_daemon_state_t
683 vscand_get_state(void)
684 {
685 	return (vscand_state);
686 }
687 
688 
689 /*
690  * vscand_get_viruslog
691  */
692 static int
693 vscand_get_viruslog()
694 {
695 	vs_props_t props;
696 	uint64_t propids;
697 	int rc;
698 
699 	propids = VS_PROPID_VLOG;
700 	if ((rc = vs_props_get(&props, propids)) != VS_ERR_NONE) {
701 		vscand_error(vs_strerror(rc));
702 		return (-1);
703 	}
704 
705 	(void) strlcpy(vscand_vlog, props.vp_vlog, sizeof (vscand_vlog));
706 	return (0);
707 }
708 
709 
710 /*
711  * vscand_viruslog
712  */
713 char *
714 vscand_viruslog(void)
715 {
716 	if (vscand_vlog[0] == '\0')
717 		return (NULL);
718 
719 	return (vscand_vlog);
720 }
721 
722 
723 /*
724  * vscand_kernel_bind
725  */
726 static int
727 vscand_kernel_bind(void)
728 {
729 	char devname[MAXPATHLEN];
730 	int inst = 0;
731 
732 	(void) snprintf(devname, MAXPATHLEN, "%s%d", VS_DRV_PATH, inst);
733 
734 	if ((vscand_kdrv_fd = open(devname, O_RDONLY)) < 0) {
735 		vscand_error(gettext("failed to bind to kernel"));
736 		return (-1);
737 	}
738 
739 	return (0);
740 }
741 
742 
743 /*
744  * vscand_kernel_unbind
745  */
746 static void
747 vscand_kernel_unbind(void)
748 {
749 	if (vscand_kdrv_fd >= 0)
750 		(void) close(vscand_kdrv_fd);
751 }
752 
753 
754 /*
755  * vscand_kernel_enable
756  */
757 static int
758 vscand_kernel_enable(int door_fd)
759 {
760 	if (ioctl(vscand_kdrv_fd, VS_IOCTL_ENABLE, door_fd) < 0) {
761 		vscand_error(gettext("failed to bind to kernel"));
762 		(void) close(vscand_kdrv_fd);
763 		vscand_kdrv_fd = -1;
764 		return (-1);
765 	}
766 	return (0);
767 }
768 
769 
770 /*
771  * vscand_kernel_disable
772  */
773 static void
774 vscand_kernel_disable()
775 {
776 	if (vscand_kdrv_fd >= 0)
777 		(void) ioctl(vscand_kdrv_fd, VS_IOCTL_DISABLE);
778 }
779 
780 
781 /*
782  * vscand_kernel_config
783  */
784 int
785 vscand_kernel_config(vs_config_t *conf)
786 {
787 	if ((vscand_kdrv_fd < 0) ||
788 	    (ioctl(vscand_kdrv_fd, VS_IOCTL_CONFIG, conf) < 0)) {
789 		vscand_error(gettext("failed to send config to kernel"));
790 		return (-1);
791 	}
792 
793 	return (0);
794 }
795 
796 
797 /*
798  * vscand_kernel_result
799  */
800 int
801 vscand_kernel_result(vs_scan_rsp_t *scan_rsp)
802 {
803 	if ((vscand_kdrv_fd < 0) ||
804 	    (ioctl(vscand_kdrv_fd, VS_IOCTL_RESULT, scan_rsp) < 0)) {
805 		vscand_error(gettext("failed to send result to kernel"));
806 		return (-1);
807 	}
808 
809 	return (0);
810 }
811 
812 
813 /*
814  * vscand_kernel_max_req
815  */
816 int
817 vscand_kernel_max_req(uint32_t *max_req)
818 {
819 	if ((vscand_kdrv_fd < 0) ||
820 	    (ioctl(vscand_kdrv_fd, VS_IOCTL_MAX_REQ, max_req) < 0)) {
821 		vscand_error(gettext("failed to get config data from kernel"));
822 		return (-1);
823 	}
824 
825 	return (0);
826 }
827 
828 
829 /*
830  * vscand_set_resource_limits
831  *
832  * If the process's max file descriptor limit is less than
833  * VS_FILE_DESCRIPTORS, increae it to VS_FILE_DESCRIPTORS.
834  */
835 static int
836 vscand_set_resource_limits(void)
837 {
838 	int rc = -1;
839 	rctlblk_t *rblk;
840 	char *limit = "process.max-file-descriptor";
841 
842 	rblk = (rctlblk_t *)malloc(rctlblk_size());
843 
844 	if (rblk != NULL) {
845 		rc = getrctl(limit, NULL, rblk, 0);
846 		if ((rc == 0) &&
847 		    (rctlblk_get_value(rblk) < VS_FILE_DESCRIPTORS)) {
848 			rctlblk_set_value(rblk, VS_FILE_DESCRIPTORS);
849 			rc = setrctl(limit, NULL, rblk, 0);
850 		}
851 		(void) free(rblk);
852 	}
853 
854 	return (rc);
855 }
856 
857 
858 /*
859  * vscand_error
860  */
861 static void
862 vscand_error(const char *errmsg)
863 {
864 	(void) fprintf(stderr, "vscand: %s", errmsg);
865 	syslog(LOG_ERR, "%s\n", errmsg);
866 }
867 
868 
869 /*
870  * vscand_dtrace_cfg
871  * vscand_dtrace_gen
872  * vscand_dtrace_eng
873  *
874  * Support for dtracing vscand configuration when processing
875  * a reconfiguration event (SIGHUP)
876  */
877 /*ARGSUSED*/
878 static void
879 vscand_dtrace_eng(char *id, boolean_t enable, char *host, int port, int conn)
880 {
881 }
882 /*ARGSUSED*/
883 static void
884 vscand_dtrace_gen(char *size, boolean_t action, char *types, char *log)
885 {
886 }
887 static void
888 vscand_dtrace_cfg(vs_props_all_t *config)
889 {
890 	int i;
891 
892 	vscand_dtrace_gen(config->va_props.vp_maxsize,
893 	    config->va_props.vp_maxsize_action,
894 	    config->va_props.vp_types,
895 	    config->va_props.vp_vlog);
896 
897 	for (i = 0; i < VS_SE_MAX; i++) {
898 		if (config->va_se[i].vep_engid[0] != 0)
899 				vscand_dtrace_eng(config->va_se[i].vep_engid,
900 				    config->va_se[i].vep_enable,
901 				    config->va_se[i].vep_host,
902 				    config->va_se[i].vep_port,
903 				    config->va_se[i].vep_maxconn);
904 	}
905 }
906