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