xref: /onnv-gate/usr/src/cmd/vscan/vscand/vs_main.c (revision 8334:5f1c6a3b0fad)
15440Sjm199354 /*
25440Sjm199354  * CDDL HEADER START
35440Sjm199354  *
45440Sjm199354  * The contents of this file are subject to the terms of the
55440Sjm199354  * Common Development and Distribution License (the "License").
65440Sjm199354  * You may not use this file except in compliance with the License.
75440Sjm199354  *
85440Sjm199354  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95440Sjm199354  * or http://www.opensolaris.org/os/licensing.
105440Sjm199354  * See the License for the specific language governing permissions
115440Sjm199354  * and limitations under the License.
125440Sjm199354  *
135440Sjm199354  * When distributing Covered Code, include this CDDL HEADER in each
145440Sjm199354  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155440Sjm199354  * If applicable, add the following below this CDDL HEADER, with the
165440Sjm199354  * fields enclosed by brackets "[]" replaced with your own identifying
175440Sjm199354  * information: Portions Copyright [yyyy] [name of copyright owner]
185440Sjm199354  *
195440Sjm199354  * CDDL HEADER END
205440Sjm199354  */
215440Sjm199354 /*
226407Sjm199354  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
235440Sjm199354  * Use is subject to license terms.
245440Sjm199354  */
255440Sjm199354 
265440Sjm199354 /*
275440Sjm199354  * vscand Daemon Program
285440Sjm199354  */
295440Sjm199354 
305440Sjm199354 #include <stdio.h>
315440Sjm199354 #include <sys/stat.h>
325440Sjm199354 #include <sys/filio.h>
335440Sjm199354 #include <sys/types.h>
345440Sjm199354 #include <sys/socket.h>
355440Sjm199354 #include <sys/ioctl.h>
365440Sjm199354 #include <sys/param.h>
375440Sjm199354 #include <zone.h>
385440Sjm199354 #include <tsol/label.h>
395440Sjm199354 #include <string.h>
405440Sjm199354 #include <stdlib.h>
415440Sjm199354 #include <fcntl.h>
425440Sjm199354 #include <wait.h>
435440Sjm199354 #include <unistd.h>
445440Sjm199354 #include <getopt.h>
455440Sjm199354 #include <stdarg.h>
465440Sjm199354 #include <libscf.h>
475440Sjm199354 #include <signal.h>
48*8334SJose.Borrego@Sun.COM #include <atomic.h>
495440Sjm199354 #include <libintl.h>
505440Sjm199354 #include <netinet/in.h>
515440Sjm199354 #include <arpa/inet.h>
525440Sjm199354 #include <ctype.h>
535440Sjm199354 #include <pthread.h>
545440Sjm199354 #include <syslog.h>
555440Sjm199354 #include <locale.h>
565440Sjm199354 #include <pwd.h>
575440Sjm199354 #include <grp.h>
585440Sjm199354 #include <priv_utils.h>
596407Sjm199354 #include <rctl.h>
605440Sjm199354 #include "vs_incl.h"
615440Sjm199354 
626407Sjm199354 #define	VS_FILE_DESCRIPTORS	512
636407Sjm199354 
645440Sjm199354 static int vscand_fg = 0; /* daemon by default */
655440Sjm199354 static vs_daemon_state_t vscand_state = VS_STATE_INIT;
66*8334SJose.Borrego@Sun.COM static volatile uint_t vscand_sigval = 0;
67*8334SJose.Borrego@Sun.COM static volatile uint_t vscand_n_refresh = 0;
685440Sjm199354 static int vscand_kdrv_fd = -1;
695440Sjm199354 static pthread_mutex_t vscand_cfg_mutex = PTHREAD_MUTEX_INITIALIZER;
706407Sjm199354 static pthread_cond_t vscand_cfg_cv;
716407Sjm199354 static pthread_t vscand_cfg_tid = 0;
725440Sjm199354 
735440Sjm199354 /* virus log path */
745440Sjm199354 static char vscand_vlog[MAXPATHLEN];
755440Sjm199354 
765440Sjm199354 /* user and group ids - default to 0 */
775440Sjm199354 static uid_t root_uid = 0, daemon_uid = 0;
785440Sjm199354 static gid_t sys_gid = 0;
795440Sjm199354 
805440Sjm199354 
815440Sjm199354 /* local function prototypes */
825440Sjm199354 static void vscand_sig_handler(int);
835440Sjm199354 static int vscand_parse_args(int, char **);
845440Sjm199354 static void vscand_get_uid_gid();
855440Sjm199354 static int vscand_init_file(char *, uid_t, gid_t, mode_t);
865440Sjm199354 static void vscand_usage(char *);
875440Sjm199354 static int vscand_daemonize_init(void);
885440Sjm199354 static void vscand_daemonize_fini(int, int);
895440Sjm199354 static int vscand_init(void);
905440Sjm199354 static void vscand_fini(void);
916407Sjm199354 static int vscand_cfg_init(void);
926407Sjm199354 static void vscand_cfg_fini(void);
936407Sjm199354 static void *vscand_cfg_handler(void *);
945440Sjm199354 static int vscand_configure(void);
956407Sjm199354 static void vscand_dtrace_cfg(vs_props_all_t *);
965440Sjm199354 static int vscand_kernel_bind(void);
975440Sjm199354 static void vscand_kernel_unbind(void);
985440Sjm199354 static int vscand_kernel_enable(int);
995440Sjm199354 static void vscand_kernel_disable(void);
1005440Sjm199354 static int vscand_kernel_config(vs_config_t *);
1016407Sjm199354 static int vscand_kernel_max_req(uint32_t *);
1025440Sjm199354 static void vscand_error(const char *);
1035440Sjm199354 static int vscand_get_viruslog(void);
1046407Sjm199354 static int vscand_set_resource_limits(void);
1055440Sjm199354 
1065440Sjm199354 
1075440Sjm199354 /*
1085440Sjm199354  * Enable libumem debugging by default on DEBUG builds.
1095440Sjm199354  */
1105440Sjm199354 #ifdef DEBUG
1115440Sjm199354 const char *
_umem_debug_init(void)1125440Sjm199354 _umem_debug_init(void)
1135440Sjm199354 {
1145440Sjm199354 	return ("default,verbose"); /* $UMEM_DEBUG setting */
1155440Sjm199354 }
1165440Sjm199354 
1175440Sjm199354 const char *
_umem_logging_init(void)1185440Sjm199354 _umem_logging_init(void)
1195440Sjm199354 {
1205440Sjm199354 	return ("fail,contents"); /* $UMEM_LOGGING setting */
1215440Sjm199354 }
1225440Sjm199354 #endif
1235440Sjm199354 
1245440Sjm199354 
1255440Sjm199354 /*
126*8334SJose.Borrego@Sun.COM  * vscand_sig_handler
1275440Sjm199354  */
1285440Sjm199354 static void
vscand_sig_handler(int sig)1295440Sjm199354 vscand_sig_handler(int sig)
1305440Sjm199354 {
1315440Sjm199354 	if (vscand_sigval == 0)
132*8334SJose.Borrego@Sun.COM 		(void) atomic_swap_uint(&vscand_sigval, sig);
133*8334SJose.Borrego@Sun.COM 
134*8334SJose.Borrego@Sun.COM 	if (sig == SIGHUP)
135*8334SJose.Borrego@Sun.COM 		atomic_inc_uint(&vscand_n_refresh);
1365440Sjm199354 }
1375440Sjm199354 
1385440Sjm199354 
1395440Sjm199354 /*
1405440Sjm199354  * main
1415440Sjm199354  *
1425440Sjm199354  * main must return SMF return code (see smf_method (5)) if vscand
1435440Sjm199354  * is invoked directly by smf (see manifest: vscan.xml)
1445440Sjm199354  * Exit codes: SMF_EXIT_ERR_CONFIG - error
1455440Sjm199354  *             SMF_EXIT_ERR_FATAL - fatal error
1465440Sjm199354  *             SMF_EXIT_OK - success
1475440Sjm199354  */
1485440Sjm199354 int
main(int argc,char ** argv)1495440Sjm199354 main(int argc, char **argv)
1505440Sjm199354 {
1515440Sjm199354 	int err_stat = 0, pfd = -1;
1525440Sjm199354 	sigset_t set;
1535440Sjm199354 	struct sigaction act;
1546407Sjm199354 	int sigval;
1556407Sjm199354 
1565440Sjm199354 	mode_t log_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
1575440Sjm199354 	mode_t door_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
1585440Sjm199354 
1595440Sjm199354 	(void) setlocale(LC_ALL, "");
1605440Sjm199354 	openlog("vscand", 0, LOG_DAEMON);
1615440Sjm199354 
1625440Sjm199354 	/* check if running in global zone; other zones not supported */
1635440Sjm199354 	if (getzoneid() != GLOBAL_ZONEID) {
1645440Sjm199354 		vscand_error(gettext("non-global zone not supported"));
1655440Sjm199354 		exit(SMF_EXIT_ERR_FATAL);
1665440Sjm199354 	}
1675440Sjm199354 
1685440Sjm199354 	/* check for a Trusted Solaris environment; not supported */
1695440Sjm199354 	if (is_system_labeled()) {
1705440Sjm199354 		vscand_error(gettext("Trusted Extensions not supported"));
1715440Sjm199354 		exit(SMF_EXIT_ERR_FATAL);
1725440Sjm199354 	}
1735440Sjm199354 
1745440Sjm199354 	/* Parse arguments */
1755440Sjm199354 	if (vscand_parse_args(argc, argv) != 0)
1765440Sjm199354 		exit(SMF_EXIT_ERR_CONFIG);
1775440Sjm199354 
1785440Sjm199354 	vscand_get_uid_gid();
1795440Sjm199354 
1805440Sjm199354 	/*
1815440Sjm199354 	 * Initializetion of virus log and statistic door file
1825440Sjm199354 	 * MUST be done BEFORE vscand_daemonize_init resets uid/gid.
1835440Sjm199354 	 * Only root can create the files in /var/log and /var/run.
1845440Sjm199354 	 */
1855440Sjm199354 	if ((vscand_get_viruslog() != 0) ||
1865440Sjm199354 	    (vscand_vlog[0] == '\0') ||
1875440Sjm199354 	    (vscand_init_file(vscand_vlog, root_uid, sys_gid, log_mode) != 0)) {
1885440Sjm199354 		*vscand_vlog = 0;
1895440Sjm199354 	}
1905440Sjm199354 
1915440Sjm199354 	(void) vscand_init_file(VS_STATS_DOOR_NAME,
1925440Sjm199354 	    daemon_uid, sys_gid, door_mode);
1935440Sjm199354 
1945440Sjm199354 	/*
1955440Sjm199354 	 * Once we're done setting our global state up, set up signal handlers
1966407Sjm199354 	 * for ensuring orderly termination on SIGTERM.
1975440Sjm199354 	 */
1985440Sjm199354 	(void) sigfillset(&set);
1995440Sjm199354 	(void) sigdelset(&set, SIGABRT); /* always unblocked for ASSERT() */
2005440Sjm199354 
2015440Sjm199354 	(void) sigfillset(&act.sa_mask);
2025440Sjm199354 	act.sa_handler = vscand_sig_handler;
2035440Sjm199354 	act.sa_flags = 0;
2045440Sjm199354 
2055440Sjm199354 	(void) sigaction(SIGTERM, &act, NULL);
2065440Sjm199354 	(void) sigaction(SIGHUP, &act, NULL); /* Refresh config */
2075440Sjm199354 	(void) sigaction(SIGINT, &act, NULL);
2086407Sjm199354 	(void) sigaction(SIGPIPE, &act, NULL);
2095440Sjm199354 	(void) sigdelset(&set, SIGTERM);
2105440Sjm199354 	(void) sigdelset(&set, SIGHUP);
2115440Sjm199354 	(void) sigdelset(&set, SIGINT);
2126407Sjm199354 	(void) sigdelset(&set, SIGPIPE);
2135440Sjm199354 
2145440Sjm199354 	if (vscand_fg) {
2155440Sjm199354 		(void) sigdelset(&set, SIGTSTP);
2165440Sjm199354 		(void) sigdelset(&set, SIGTTIN);
2175440Sjm199354 		(void) sigdelset(&set, SIGTTOU);
2185440Sjm199354 
2195440Sjm199354 		if (vscand_init() != 0) {
2205440Sjm199354 			vscand_error(gettext("failed to initialize service"));
2215440Sjm199354 			exit(SMF_EXIT_ERR_CONFIG);
2225440Sjm199354 		}
2235440Sjm199354 	} else {
2245440Sjm199354 		/*
2255440Sjm199354 		 * "pfd" is a pipe descriptor -- any fatal errors
2265440Sjm199354 		 * during subsequent initialization of the child
2275440Sjm199354 		 * process should be written to this pipe and the
2285440Sjm199354 		 * parent will report this error as the exit status.
2295440Sjm199354 		 */
2305440Sjm199354 		pfd = vscand_daemonize_init();
2315440Sjm199354 
2325440Sjm199354 		if (vscand_init() != 0) {
2335440Sjm199354 			vscand_error(gettext("failed to initialize service"));
2345440Sjm199354 			exit(SMF_EXIT_ERR_CONFIG);
2355440Sjm199354 		}
2365440Sjm199354 
2375440Sjm199354 		vscand_daemonize_fini(pfd, err_stat);
2385440Sjm199354 	}
2395440Sjm199354 
2405440Sjm199354 	vscand_state = VS_STATE_RUNNING;
2415440Sjm199354 
2425440Sjm199354 	/* Wait here until shutdown */
2435440Sjm199354 	while (vscand_state == VS_STATE_RUNNING) {
244*8334SJose.Borrego@Sun.COM 		if (vscand_sigval == 0 && vscand_n_refresh == 0)
2456407Sjm199354 			(void) sigsuspend(&set);
2465440Sjm199354 
247*8334SJose.Borrego@Sun.COM 		sigval = atomic_swap_uint(&vscand_sigval, 0);
2486407Sjm199354 
2496407Sjm199354 		switch (sigval) {
2505440Sjm199354 		case 0:
2516407Sjm199354 		case SIGPIPE:
2525440Sjm199354 		case SIGHUP:
2535440Sjm199354 			break;
2545440Sjm199354 		default:
2555440Sjm199354 			vscand_state = VS_STATE_SHUTDOWN;
2565440Sjm199354 			break;
2575440Sjm199354 		}
258*8334SJose.Borrego@Sun.COM 
259*8334SJose.Borrego@Sun.COM 		if (atomic_swap_uint(&vscand_n_refresh, 0) != 0)
260*8334SJose.Borrego@Sun.COM 			(void) pthread_cond_signal(&vscand_cfg_cv);
2615440Sjm199354 	}
2625440Sjm199354 
2635440Sjm199354 	vscand_fini();
2645440Sjm199354 	return (SMF_EXIT_OK);
2655440Sjm199354 }
2665440Sjm199354 
2675440Sjm199354 
2685440Sjm199354 /*
2696407Sjm199354  * vscand_parse_args
2705440Sjm199354  * Routine to parse the arguments to the daemon program
2715440Sjm199354  * 'f' argument runs process in the foreground instead of as a daemon
2725440Sjm199354  */
2735440Sjm199354 int
vscand_parse_args(int argc,char ** argv)2745440Sjm199354 vscand_parse_args(int argc, char **argv)
2755440Sjm199354 {
2765440Sjm199354 	int	optchar;
2775440Sjm199354 
2785440Sjm199354 	while ((optchar = getopt(argc, argv, "f?")) != EOF) {
2795440Sjm199354 		switch (optchar) {
2805440Sjm199354 		case 'f':
2815440Sjm199354 			vscand_fg = 1;
2825440Sjm199354 			break;
2835440Sjm199354 		default:
2845440Sjm199354 			vscand_usage(argv[0]);
2855440Sjm199354 			return (-1);
2865440Sjm199354 		}
2875440Sjm199354 	}
2885440Sjm199354 	return (0);
2895440Sjm199354 }
2905440Sjm199354 
2915440Sjm199354 
2925440Sjm199354 /*
2935440Sjm199354  * vscand_usage
2945440Sjm199354  */
2955440Sjm199354 static void
vscand_usage(char * progname)2965440Sjm199354 vscand_usage(char *progname)
2975440Sjm199354 {
2985440Sjm199354 	char buf[128];
2995440Sjm199354 
3005440Sjm199354 	(void) snprintf(buf, sizeof (buf), "%s %s [-f]",
3015440Sjm199354 	    gettext("Usage"), progname);
3025440Sjm199354 	vscand_error(buf);
3035440Sjm199354 
3045440Sjm199354 	(void) snprintf(buf, sizeof (buf), "\t-f %s\n",
3055440Sjm199354 	    gettext("run program in foreground"));
3065440Sjm199354 	vscand_error(buf);
3075440Sjm199354 }
3085440Sjm199354 
3095440Sjm199354 
3105440Sjm199354 /*
3115440Sjm199354  * vscand_get_uid_gid
3125440Sjm199354  *
3135440Sjm199354  * failure to access a uid/gid results in the default (0) being used.
3145440Sjm199354  */
3155440Sjm199354 static void
vscand_get_uid_gid()3165440Sjm199354 vscand_get_uid_gid()
3175440Sjm199354 {
3185440Sjm199354 	struct passwd *pwd;
3195440Sjm199354 	struct group *grp;
3205440Sjm199354 
3215440Sjm199354 	if ((pwd = getpwnam("root")) != NULL)
3225440Sjm199354 		root_uid = pwd->pw_uid;
3235440Sjm199354 
3245440Sjm199354 	if ((pwd = getpwnam("daemon")) != NULL)
3255440Sjm199354 		daemon_uid = pwd->pw_uid;
3265440Sjm199354 
3275440Sjm199354 	if ((grp = getgrnam("sys")) != NULL)
3285440Sjm199354 		sys_gid = grp->gr_gid;
3295440Sjm199354 }
3305440Sjm199354 
3315440Sjm199354 
3325440Sjm199354 /*
3335440Sjm199354  * vscand_daemonize_init
3345440Sjm199354  *
3355440Sjm199354  * This function will fork off a child process, from which
3365440Sjm199354  * only the child will return.
3375440Sjm199354  */
3385440Sjm199354 static int
vscand_daemonize_init(void)3395440Sjm199354 vscand_daemonize_init(void)
3405440Sjm199354 {
3415440Sjm199354 	int status, pfds[2];
3425440Sjm199354 	sigset_t set, oset;
3435440Sjm199354 	pid_t pid;
3445440Sjm199354 
3455440Sjm199354 	/*
3465440Sjm199354 	 * Reset process owner/group to daemon/sys. Root ownership is only
3475440Sjm199354 	 * required to initialize virus log file in /var/log
3485440Sjm199354 	 */
3495440Sjm199354 	if (__init_daemon_priv(PU_RESETGROUPS | PU_LIMITPRIVS,
3505440Sjm199354 	    daemon_uid, sys_gid,
3515440Sjm199354 	    PRIV_PROC_AUDIT, PRIV_FILE_DAC_SEARCH, PRIV_FILE_DAC_READ,
3525440Sjm199354 	    PRIV_FILE_FLAG_SET, NULL) != 0) {
3535440Sjm199354 		vscand_error(gettext("failed to initialize privileges"));
3545440Sjm199354 		_exit(SMF_EXIT_ERR_FATAL);
3555440Sjm199354 	}
3565440Sjm199354 
3575440Sjm199354 	/*
3585440Sjm199354 	 * Block all signals prior to the fork and leave them blocked in the
3595440Sjm199354 	 * parent so we don't get in a situation where the parent gets SIGINT
3605440Sjm199354 	 * and returns non-zero exit status and the child is actually running.
3615440Sjm199354 	 * In the child, restore the signal mask once we've done our setsid().
3625440Sjm199354 	 */
3635440Sjm199354 	(void) sigfillset(&set);
3645440Sjm199354 	(void) sigdelset(&set, SIGABRT);
3655440Sjm199354 	(void) sigprocmask(SIG_BLOCK, &set, &oset);
3665440Sjm199354 
3675440Sjm199354 	if (pipe(pfds) == -1) {
3685440Sjm199354 		vscand_error(gettext("failed to create pipe for daemonize"));
3695440Sjm199354 		_exit(SMF_EXIT_ERR_FATAL);
3705440Sjm199354 	}
3715440Sjm199354 
3725440Sjm199354 	if ((pid = fork()) == -1) {
3735440Sjm199354 		vscand_error(gettext("failed to fork for daemonize"));
3745440Sjm199354 		_exit(SMF_EXIT_ERR_FATAL);
3755440Sjm199354 	}
3765440Sjm199354 
3775440Sjm199354 	/*
3785440Sjm199354 	 * If we're the parent process, wait for either the child to send us
3795440Sjm199354 	 * the appropriate exit status over the pipe or for the read to fail
3805440Sjm199354 	 * (presumably with 0 for EOF if our child terminated abnormally).
3815440Sjm199354 	 * If the read fails, exit with either the child's exit status if it
3825440Sjm199354 	 * exited or with SMF_EXIT_ERR_FATAL if it died from a fatal signal.
3835440Sjm199354 	 */
3845440Sjm199354 	if (pid != 0) {
3855440Sjm199354 		(void) close(pfds[1]);
3865440Sjm199354 
3875440Sjm199354 		if (read(pfds[0], &status, sizeof (status)) == sizeof (status))
3885440Sjm199354 			_exit(status);
3895440Sjm199354 
3905440Sjm199354 		if (waitpid(pid, &status, 0) == pid && WIFEXITED(status))
3915440Sjm199354 			_exit(WEXITSTATUS(status));
3925440Sjm199354 
3935440Sjm199354 		vscand_error(gettext("failed to daemonize"));
3945440Sjm199354 		_exit(SMF_EXIT_ERR_FATAL);
3955440Sjm199354 	}
3965440Sjm199354 
3975440Sjm199354 
3985440Sjm199354 	(void) setsid();
3995440Sjm199354 	(void) sigprocmask(SIG_SETMASK, &oset, NULL);
4005440Sjm199354 	(void) chdir("/");
4015440Sjm199354 	(void) umask(022);
4025440Sjm199354 	(void) close(pfds[0]);
4035440Sjm199354 
4045440Sjm199354 	return (pfds[1]);
4055440Sjm199354 }
4065440Sjm199354 
4075440Sjm199354 
4085440Sjm199354 /*
4095440Sjm199354  * vscand_daemonize_fini
4105440Sjm199354  * Now that we're running, if a pipe fd was specified, write an exit
4115440Sjm199354  * status to it to indicate that our parent process can safely detach.
4125440Sjm199354  */
4135440Sjm199354 static void
vscand_daemonize_fini(int fd,int err_status)4145440Sjm199354 vscand_daemonize_fini(int fd, int err_status)
4155440Sjm199354 {
4165440Sjm199354 	if (fd >= 0)
4175440Sjm199354 		(void) write(fd, &err_status, sizeof (err_status));
4185440Sjm199354 
4195440Sjm199354 	(void) close(fd);
4205440Sjm199354 
4215440Sjm199354 	/* Restore standard file descriptors */
4225440Sjm199354 	if ((fd = open("/dev/null", O_RDWR)) >= 0) {
4235440Sjm199354 		(void) fcntl(fd, F_DUP2FD, STDIN_FILENO);
4245440Sjm199354 		(void) fcntl(fd, F_DUP2FD, STDOUT_FILENO);
4255440Sjm199354 		(void) fcntl(fd, F_DUP2FD, STDERR_FILENO);
4265440Sjm199354 		(void) close(fd);
4275440Sjm199354 	}
4285440Sjm199354 
4295440Sjm199354 	/* clear basic privileges not required by vscand */
4305440Sjm199354 	__fini_daemon_priv(PRIV_PROC_FORK, PRIV_PROC_EXEC, PRIV_PROC_SESSION,
4315440Sjm199354 	    PRIV_FILE_LINK_ANY, PRIV_PROC_INFO, (char *)NULL);
4325440Sjm199354 }
4335440Sjm199354 
4345440Sjm199354 
4355440Sjm199354 /*
4365440Sjm199354  * vscand_init_file
4375440Sjm199354  *
4385440Sjm199354  * create specified file and set its uid, gid and mode
4395440Sjm199354  */
4405440Sjm199354 static int
vscand_init_file(char * filepath,uid_t uid,gid_t gid,mode_t access_mode)4416407Sjm199354 vscand_init_file(char *filepath, uid_t uid, gid_t gid, mode_t access_mode)
4425440Sjm199354 {
4435440Sjm199354 	int fd, rc = 0;
4445440Sjm199354 	struct stat stat_buf;
4455440Sjm199354 	char buf[MAXPATHLEN];
4465440Sjm199354 
4476407Sjm199354 	if ((fd = open(filepath, O_RDONLY | O_CREAT, access_mode)) == -1) {
4485440Sjm199354 		rc = -1;
4496407Sjm199354 	} else {
4506407Sjm199354 		if (fstat(fd, &stat_buf) != 0) {
4515440Sjm199354 			rc = -1;
4526407Sjm199354 		} else {
4536407Sjm199354 			if ((stat_buf.st_mode & S_IAMB) != access_mode) {
4546407Sjm199354 				if (fchmod(fd, access_mode) != 0)
4555440Sjm199354 					rc = -1;
4565440Sjm199354 			}
4575440Sjm199354 
4585440Sjm199354 			if ((stat_buf.st_uid != uid) ||
4595440Sjm199354 			    (stat_buf.st_gid != gid)) {
4605440Sjm199354 				if (fchown(fd, uid, gid) != 0)
4615440Sjm199354 					rc = -1;
4625440Sjm199354 			}
4635440Sjm199354 		}
4645440Sjm199354 
4655440Sjm199354 		(void) close(fd);
4665440Sjm199354 	}
4675440Sjm199354 
4685440Sjm199354 	if (rc == -1) {
4695440Sjm199354 		(void) snprintf(buf, MAXPATHLEN, "%s %s",
4705440Sjm199354 		    gettext("Failed to initialize"), filepath);
4715440Sjm199354 		vscand_error(buf);
4725440Sjm199354 	}
4735440Sjm199354 
4745440Sjm199354 	return (rc);
4755440Sjm199354 }
4765440Sjm199354 
4775440Sjm199354 
4785440Sjm199354 /*
4795440Sjm199354  * vscand_init
4805440Sjm199354  *
4815440Sjm199354  * There are some requirements on the order in which the daemon
4825440Sjm199354  * initialization functions are called.
4835440Sjm199354  *
4845440Sjm199354  * - vscand_kernel_bind - bind to kernel module
4855440Sjm199354  * - vs_eng_init populates vs_icap data and thus vs_icap_init MUST be
4865440Sjm199354  *   called before vs_eng_init
4875440Sjm199354  * - vscand_configure - load the configuration
4885440Sjm199354  * - vs_door_init - start vscan door server
4895440Sjm199354  * - vscand_kernel_enable - enable scan requests from kernel
4905440Sjm199354  */
4915440Sjm199354 static int
vscand_init(void)4925440Sjm199354 vscand_init(void)
4935440Sjm199354 {
4945440Sjm199354 	int door_fd = -1;
4956407Sjm199354 	uint32_t max_req;
4965440Sjm199354 
4975440Sjm199354 	if (vscand_kernel_bind() < 0)
4985440Sjm199354 		return (-1);
4995440Sjm199354 
5006407Sjm199354 	if (vscand_kernel_max_req(&max_req) == -1)
5016407Sjm199354 		return (-1);
5026407Sjm199354 
5036407Sjm199354 	if (vs_svc_init(max_req) != 0)
5046407Sjm199354 		return (-1);
5056407Sjm199354 
5065440Sjm199354 	if (vs_stats_init() != 0)
5075440Sjm199354 		vscand_error(
5085440Sjm199354 		    gettext("failed to initialize statistics interface"));
5095440Sjm199354 
5105440Sjm199354 	vs_icap_init();
5115440Sjm199354 	vs_eng_init();
5125440Sjm199354 
5136407Sjm199354 	/* initialize configuration and handler thread */
5146407Sjm199354 	if (vscand_cfg_init() != 0) {
5155440Sjm199354 		vscand_error(gettext("failed to initialize configuration"));
5166407Sjm199354 		vscand_fini();
5175440Sjm199354 		return (-1);
5185440Sjm199354 	}
5195440Sjm199354 
5206407Sjm199354 	(void) vscand_set_resource_limits();
5216407Sjm199354 
5225440Sjm199354 	if (((door_fd = vs_door_init()) < 0) ||
5235440Sjm199354 	    (vscand_kernel_enable(door_fd) < 0)) {
5245440Sjm199354 		vscand_fini();
5255440Sjm199354 		return (-1);
5265440Sjm199354 	}
5275440Sjm199354 
5285440Sjm199354 	return (0);
5295440Sjm199354 }
5305440Sjm199354 
5315440Sjm199354 
5325440Sjm199354 /*
5335440Sjm199354  * vscand_fini
5345440Sjm199354  *
5355440Sjm199354  * vscand_kernel_disable - should be called first to ensure that no
5365440Sjm199354  *	more scan requests are initiated from the kernel module
5376407Sjm199354  * vs_svc_terminate - terminate requests and wait for thread completion
5386407Sjm199354  * vs_xxx_fini - module cleanup routines
5395440Sjm199354  * vscand_kernel_unbind - should be called last to tell the kernel module
5405440Sjm199354  *	that vscand is shutdown.
5415440Sjm199354  */
5425440Sjm199354 static void
vscand_fini(void)5435440Sjm199354 vscand_fini(void)
5445440Sjm199354 {
5455440Sjm199354 	vscand_kernel_disable();
5465440Sjm199354 
5476407Sjm199354 	/* terminate reconfiguration handler thread */
5486407Sjm199354 	vscand_cfg_fini();
5496407Sjm199354 
5506407Sjm199354 	/* terminate requests and wait for completion */
5516407Sjm199354 	vs_svc_terminate();
5526407Sjm199354 
5536407Sjm199354 	/* clean up */
5545440Sjm199354 	vs_svc_fini();
5555440Sjm199354 	vs_eng_fini();
5565440Sjm199354 	vs_icap_fini();
5575440Sjm199354 	vs_door_fini();
5585440Sjm199354 	vs_stats_fini();
5595440Sjm199354 
5605440Sjm199354 	vscand_kernel_unbind();
5615440Sjm199354 }
5625440Sjm199354 
5635440Sjm199354 
5645440Sjm199354 /*
5656407Sjm199354  * vscand_cfg_init
5666407Sjm199354  *
5676407Sjm199354  * initialize configuration and reconfiguration handler thread
5686407Sjm199354  */
5696407Sjm199354 static int
vscand_cfg_init(void)5706407Sjm199354 vscand_cfg_init(void)
5716407Sjm199354 {
5726407Sjm199354 	int rc;
5736407Sjm199354 
5746407Sjm199354 	(void) pthread_cond_init(&vscand_cfg_cv, NULL);
5756407Sjm199354 
5766407Sjm199354 	(void) pthread_mutex_lock(&vscand_cfg_mutex);
5776407Sjm199354 	rc = vscand_configure();
5786407Sjm199354 	(void) pthread_mutex_unlock(&vscand_cfg_mutex);
5796407Sjm199354 
5806407Sjm199354 	if (rc != 0)
5816407Sjm199354 		return (-1);
5826407Sjm199354 
5836407Sjm199354 	if (pthread_create(&vscand_cfg_tid, NULL, vscand_cfg_handler, 0) != 0) {
5846407Sjm199354 		vscand_cfg_tid = 0;
5856407Sjm199354 		return (-1);
5866407Sjm199354 	}
5876407Sjm199354 
5886407Sjm199354 	return (0);
5896407Sjm199354 }
5906407Sjm199354 
5916407Sjm199354 
5926407Sjm199354 /*
5936407Sjm199354  * vscand_cfg_fini
5946407Sjm199354  *
5956407Sjm199354  * terminate reconfiguration handler thread
5966407Sjm199354  */
5976407Sjm199354 static void
vscand_cfg_fini()5986407Sjm199354 vscand_cfg_fini()
5996407Sjm199354 {
6006407Sjm199354 	if (vscand_cfg_tid != 0) {
6016407Sjm199354 		(void) pthread_cond_signal(&vscand_cfg_cv);
6026407Sjm199354 		(void) pthread_join(vscand_cfg_tid, NULL);
6036407Sjm199354 		vscand_cfg_tid = 0;
6046407Sjm199354 	}
6056407Sjm199354 	(void) pthread_cond_destroy(&vscand_cfg_cv);
6066407Sjm199354 }
6076407Sjm199354 
6086407Sjm199354 
6096407Sjm199354 /*
6106407Sjm199354  * vscand_cfg_handler
6116407Sjm199354  * wait for reconfiguration event and reload configuration
6126407Sjm199354  * exit on VS_STATE_SHUTDOWN
6136407Sjm199354  */
6146407Sjm199354 /*ARGSUSED*/
6156407Sjm199354 static void *
vscand_cfg_handler(void * arg)6166407Sjm199354 vscand_cfg_handler(void *arg)
6176407Sjm199354 {
6186407Sjm199354 	(void) pthread_mutex_lock(&vscand_cfg_mutex);
6196407Sjm199354 
6206407Sjm199354 	while (pthread_cond_wait(&vscand_cfg_cv, &vscand_cfg_mutex) == 0) {
6216407Sjm199354 		if (vscand_state == VS_STATE_SHUTDOWN)
6226407Sjm199354 			break;
6236407Sjm199354 
6246407Sjm199354 		(void) vscand_configure();
6256407Sjm199354 	}
6266407Sjm199354 
6276407Sjm199354 	(void) pthread_mutex_unlock(&vscand_cfg_mutex);
6286407Sjm199354 
6296407Sjm199354 	return (NULL);
6306407Sjm199354 }
6316407Sjm199354 
6326407Sjm199354 
6336407Sjm199354 /*
6345440Sjm199354  * vscand_configure
6355440Sjm199354  */
6365440Sjm199354 static int
vscand_configure(void)6375440Sjm199354 vscand_configure(void)
6385440Sjm199354 {
6395440Sjm199354 	uint32_t len;
6405440Sjm199354 	vs_config_t kconfig;
6415440Sjm199354 	vs_props_all_t config;
6425440Sjm199354 
6435440Sjm199354 	(void) memset(&config, 0, sizeof (vs_props_all_t));
6445440Sjm199354 	if (vs_props_get_all(&config) != VS_ERR_NONE) {
6455440Sjm199354 		vscand_error(gettext("configuration data error"));
6465440Sjm199354 		return (-1);
6475440Sjm199354 	}
6485440Sjm199354 
6495440Sjm199354 	(void) memset(&kconfig, 0, sizeof (vs_config_t));
6505440Sjm199354 	len = sizeof (kconfig.vsc_types);
6515440Sjm199354 	if (vs_parse_types(config.va_props.vp_types,
6525440Sjm199354 	    kconfig.vsc_types, &len) != 0) {
6535440Sjm199354 		vscand_error(gettext("configuration data error - types"));
6545440Sjm199354 		return (-1);
6555440Sjm199354 	}
6565440Sjm199354 	kconfig.vsc_types_len = len;
6575440Sjm199354 
6585440Sjm199354 	/* Convert the maxfsize string from the configuration into bytes */
6595440Sjm199354 	if (vs_strtonum(config.va_props.vp_maxsize,
6605440Sjm199354 	    &kconfig.vsc_max_size) != 0) {
6615440Sjm199354 		vscand_error(gettext("configuration data error - max-size"));
6625440Sjm199354 		return (-1);
6635440Sjm199354 	}
6645440Sjm199354 	kconfig.vsc_allow = config.va_props.vp_maxsize_action ? 1LL : 0LL;
6655440Sjm199354 
6665440Sjm199354 	/* Send configuration update to kernel */
6675440Sjm199354 	if (vscand_kernel_config(&kconfig) != 0) {
6685440Sjm199354 		return (-1);
6695440Sjm199354 	}
6705440Sjm199354 
6716407Sjm199354 	/* dtrace the configuration data */
6726407Sjm199354 	vscand_dtrace_cfg(&config);
6736407Sjm199354 
6746407Sjm199354 	/* propagate configuration changes */
6755440Sjm199354 	vs_eng_config(&config);
6765440Sjm199354 	vs_stats_config(&config);
6775440Sjm199354 
6785440Sjm199354 	return (0);
6795440Sjm199354 }
6805440Sjm199354 
6815440Sjm199354 
6825440Sjm199354 /*
6835440Sjm199354  * vscand_get_state
6845440Sjm199354  */
6855440Sjm199354 vs_daemon_state_t
vscand_get_state(void)6865440Sjm199354 vscand_get_state(void)
6875440Sjm199354 {
6885440Sjm199354 	return (vscand_state);
6895440Sjm199354 }
6905440Sjm199354 
6915440Sjm199354 
6925440Sjm199354 /*
6935440Sjm199354  * vscand_get_viruslog
6945440Sjm199354  */
6955440Sjm199354 static int
vscand_get_viruslog()6965440Sjm199354 vscand_get_viruslog()
6975440Sjm199354 {
6985440Sjm199354 	vs_props_t props;
6995440Sjm199354 	uint64_t propids;
7005440Sjm199354 	int rc;
7015440Sjm199354 
7025440Sjm199354 	propids = VS_PROPID_VLOG;
7035440Sjm199354 	if ((rc = vs_props_get(&props, propids)) != VS_ERR_NONE) {
7045440Sjm199354 		vscand_error(vs_strerror(rc));
7055440Sjm199354 		return (-1);
7065440Sjm199354 	}
7075440Sjm199354 
7085440Sjm199354 	(void) strlcpy(vscand_vlog, props.vp_vlog, sizeof (vscand_vlog));
7095440Sjm199354 	return (0);
7105440Sjm199354 }
7115440Sjm199354 
7125440Sjm199354 
7135440Sjm199354 /*
7145440Sjm199354  * vscand_viruslog
7155440Sjm199354  */
7165440Sjm199354 char *
vscand_viruslog(void)7175440Sjm199354 vscand_viruslog(void)
7185440Sjm199354 {
7195440Sjm199354 	if (vscand_vlog[0] == '\0')
7205440Sjm199354 		return (NULL);
7215440Sjm199354 
7225440Sjm199354 	return (vscand_vlog);
7235440Sjm199354 }
7245440Sjm199354 
7255440Sjm199354 
7265440Sjm199354 /*
7275440Sjm199354  * vscand_kernel_bind
7285440Sjm199354  */
7295440Sjm199354 static int
vscand_kernel_bind(void)7305440Sjm199354 vscand_kernel_bind(void)
7315440Sjm199354 {
7325440Sjm199354 	char devname[MAXPATHLEN];
7335440Sjm199354 	int inst = 0;
7345440Sjm199354 
7355440Sjm199354 	(void) snprintf(devname, MAXPATHLEN, "%s%d", VS_DRV_PATH, inst);
7365440Sjm199354 
7375440Sjm199354 	if ((vscand_kdrv_fd = open(devname, O_RDONLY)) < 0) {
7385440Sjm199354 		vscand_error(gettext("failed to bind to kernel"));
7395440Sjm199354 		return (-1);
7405440Sjm199354 	}
7415440Sjm199354 
7425440Sjm199354 	return (0);
7435440Sjm199354 }
7445440Sjm199354 
7455440Sjm199354 
7465440Sjm199354 /*
7475440Sjm199354  * vscand_kernel_unbind
7485440Sjm199354  */
7495440Sjm199354 static void
vscand_kernel_unbind(void)7505440Sjm199354 vscand_kernel_unbind(void)
7515440Sjm199354 {
7525440Sjm199354 	if (vscand_kdrv_fd >= 0)
7535440Sjm199354 		(void) close(vscand_kdrv_fd);
7545440Sjm199354 }
7555440Sjm199354 
7565440Sjm199354 
7575440Sjm199354 /*
7585440Sjm199354  * vscand_kernel_enable
7595440Sjm199354  */
7605440Sjm199354 static int
vscand_kernel_enable(int door_fd)7615440Sjm199354 vscand_kernel_enable(int door_fd)
7625440Sjm199354 {
7636407Sjm199354 	if (ioctl(vscand_kdrv_fd, VS_IOCTL_ENABLE, door_fd) < 0) {
7645440Sjm199354 		vscand_error(gettext("failed to bind to kernel"));
7655440Sjm199354 		(void) close(vscand_kdrv_fd);
7665440Sjm199354 		vscand_kdrv_fd = -1;
7675440Sjm199354 		return (-1);
7685440Sjm199354 	}
7695440Sjm199354 	return (0);
7705440Sjm199354 }
7715440Sjm199354 
7725440Sjm199354 
7735440Sjm199354 /*
7745440Sjm199354  * vscand_kernel_disable
7755440Sjm199354  */
7765440Sjm199354 static void
vscand_kernel_disable()7775440Sjm199354 vscand_kernel_disable()
7785440Sjm199354 {
7795440Sjm199354 	if (vscand_kdrv_fd >= 0)
7806407Sjm199354 		(void) ioctl(vscand_kdrv_fd, VS_IOCTL_DISABLE);
7815440Sjm199354 }
7825440Sjm199354 
7835440Sjm199354 
7845440Sjm199354 /*
7855440Sjm199354  * vscand_kernel_config
7865440Sjm199354  */
7875440Sjm199354 int
vscand_kernel_config(vs_config_t * conf)7885440Sjm199354 vscand_kernel_config(vs_config_t *conf)
7895440Sjm199354 {
7906407Sjm199354 	if ((vscand_kdrv_fd < 0) ||
7916407Sjm199354 	    (ioctl(vscand_kdrv_fd, VS_IOCTL_CONFIG, conf) < 0)) {
7925440Sjm199354 		vscand_error(gettext("failed to send config to kernel"));
7935440Sjm199354 		return (-1);
7945440Sjm199354 	}
7955440Sjm199354 
7965440Sjm199354 	return (0);
7975440Sjm199354 }
7985440Sjm199354 
7995440Sjm199354 
8005440Sjm199354 /*
8016407Sjm199354  * vscand_kernel_result
8026407Sjm199354  */
8036407Sjm199354 int
vscand_kernel_result(vs_scan_rsp_t * scan_rsp)8046407Sjm199354 vscand_kernel_result(vs_scan_rsp_t *scan_rsp)
8056407Sjm199354 {
8066407Sjm199354 	if ((vscand_kdrv_fd < 0) ||
8076407Sjm199354 	    (ioctl(vscand_kdrv_fd, VS_IOCTL_RESULT, scan_rsp) < 0)) {
8086407Sjm199354 		vscand_error(gettext("failed to send result to kernel"));
8096407Sjm199354 		return (-1);
8106407Sjm199354 	}
8116407Sjm199354 
8126407Sjm199354 	return (0);
8136407Sjm199354 }
8146407Sjm199354 
8156407Sjm199354 
8166407Sjm199354 /*
8176407Sjm199354  * vscand_kernel_max_req
8186407Sjm199354  */
8196407Sjm199354 int
vscand_kernel_max_req(uint32_t * max_req)8206407Sjm199354 vscand_kernel_max_req(uint32_t *max_req)
8216407Sjm199354 {
8226407Sjm199354 	if ((vscand_kdrv_fd < 0) ||
8236407Sjm199354 	    (ioctl(vscand_kdrv_fd, VS_IOCTL_MAX_REQ, max_req) < 0)) {
8246407Sjm199354 		vscand_error(gettext("failed to get config data from kernel"));
8256407Sjm199354 		return (-1);
8266407Sjm199354 	}
8276407Sjm199354 
8286407Sjm199354 	return (0);
8296407Sjm199354 }
8306407Sjm199354 
8316407Sjm199354 
8326407Sjm199354 /*
8336407Sjm199354  * vscand_set_resource_limits
8346407Sjm199354  *
8356407Sjm199354  * If the process's max file descriptor limit is less than
8366407Sjm199354  * VS_FILE_DESCRIPTORS, increae it to VS_FILE_DESCRIPTORS.
8376407Sjm199354  */
8386407Sjm199354 static int
vscand_set_resource_limits(void)8396407Sjm199354 vscand_set_resource_limits(void)
8406407Sjm199354 {
8416407Sjm199354 	int rc = -1;
8426407Sjm199354 	rctlblk_t *rblk;
8436407Sjm199354 	char *limit = "process.max-file-descriptor";
8446407Sjm199354 
8456407Sjm199354 	rblk = (rctlblk_t *)malloc(rctlblk_size());
8466407Sjm199354 
8476407Sjm199354 	if (rblk != NULL) {
8486407Sjm199354 		rc = getrctl(limit, NULL, rblk, 0);
8496407Sjm199354 		if ((rc == 0) &&
8506407Sjm199354 		    (rctlblk_get_value(rblk) < VS_FILE_DESCRIPTORS)) {
8516407Sjm199354 			rctlblk_set_value(rblk, VS_FILE_DESCRIPTORS);
8526407Sjm199354 			rc = setrctl(limit, NULL, rblk, 0);
8536407Sjm199354 		}
8546407Sjm199354 		(void) free(rblk);
8556407Sjm199354 	}
8566407Sjm199354 
8576407Sjm199354 	return (rc);
8586407Sjm199354 }
8596407Sjm199354 
8606407Sjm199354 
8616407Sjm199354 /*
8625440Sjm199354  * vscand_error
8635440Sjm199354  */
8645440Sjm199354 static void
vscand_error(const char * errmsg)8655440Sjm199354 vscand_error(const char *errmsg)
8665440Sjm199354 {
8675440Sjm199354 	(void) fprintf(stderr, "vscand: %s", errmsg);
8685440Sjm199354 	syslog(LOG_ERR, "%s\n", errmsg);
8695440Sjm199354 }
8706407Sjm199354 
8716407Sjm199354 
8726407Sjm199354 /*
8736407Sjm199354  * vscand_dtrace_cfg
8746407Sjm199354  * vscand_dtrace_gen
8756407Sjm199354  * vscand_dtrace_eng
8766407Sjm199354  *
8776407Sjm199354  * Support for dtracing vscand configuration when processing
8786407Sjm199354  * a reconfiguration event (SIGHUP)
8796407Sjm199354  */
8806407Sjm199354 /*ARGSUSED*/
8816407Sjm199354 static void
vscand_dtrace_eng(char * id,boolean_t enable,char * host,int port,int conn)8826407Sjm199354 vscand_dtrace_eng(char *id, boolean_t enable, char *host, int port, int conn)
8836407Sjm199354 {
8846407Sjm199354 }
8856407Sjm199354 /*ARGSUSED*/
8866407Sjm199354 static void
vscand_dtrace_gen(char * size,boolean_t action,char * types,char * log)8876407Sjm199354 vscand_dtrace_gen(char *size, boolean_t action, char *types, char *log)
8886407Sjm199354 {
8896407Sjm199354 }
8906407Sjm199354 static void
vscand_dtrace_cfg(vs_props_all_t * config)8916407Sjm199354 vscand_dtrace_cfg(vs_props_all_t *config)
8926407Sjm199354 {
8936407Sjm199354 	int i;
8946407Sjm199354 
8956407Sjm199354 	vscand_dtrace_gen(config->va_props.vp_maxsize,
8966407Sjm199354 	    config->va_props.vp_maxsize_action,
8976407Sjm199354 	    config->va_props.vp_types,
8986407Sjm199354 	    config->va_props.vp_vlog);
8996407Sjm199354 
9006407Sjm199354 	for (i = 0; i < VS_SE_MAX; i++) {
9016407Sjm199354 		if (config->va_se[i].vep_engid[0] != 0)
9026407Sjm199354 				vscand_dtrace_eng(config->va_se[i].vep_engid,
9036407Sjm199354 				    config->va_se[i].vep_enable,
9046407Sjm199354 				    config->va_se[i].vep_host,
9056407Sjm199354 				    config->va_se[i].vep_port,
9066407Sjm199354 				    config->va_se[i].vep_maxconn);
9076407Sjm199354 	}
9086407Sjm199354 }
909