1911106dfSjm199354 /* 2911106dfSjm199354 * CDDL HEADER START 3911106dfSjm199354 * 4911106dfSjm199354 * The contents of this file are subject to the terms of the 5911106dfSjm199354 * Common Development and Distribution License (the "License"). 6911106dfSjm199354 * You may not use this file except in compliance with the License. 7911106dfSjm199354 * 8911106dfSjm199354 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9911106dfSjm199354 * or http://www.opensolaris.org/os/licensing. 10911106dfSjm199354 * See the License for the specific language governing permissions 11911106dfSjm199354 * and limitations under the License. 12911106dfSjm199354 * 13911106dfSjm199354 * When distributing Covered Code, include this CDDL HEADER in each 14911106dfSjm199354 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15911106dfSjm199354 * If applicable, add the following below this CDDL HEADER, with the 16911106dfSjm199354 * fields enclosed by brackets "[]" replaced with your own identifying 17911106dfSjm199354 * information: Portions Copyright [yyyy] [name of copyright owner] 18911106dfSjm199354 * 19911106dfSjm199354 * CDDL HEADER END 20911106dfSjm199354 */ 21911106dfSjm199354 /* 22bfc848c6Sjm199354 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23911106dfSjm199354 * Use is subject to license terms. 24911106dfSjm199354 */ 25911106dfSjm199354 26911106dfSjm199354 /* 27911106dfSjm199354 * vscand Daemon Program 28911106dfSjm199354 */ 29911106dfSjm199354 30911106dfSjm199354 #include <stdio.h> 31911106dfSjm199354 #include <sys/stat.h> 32911106dfSjm199354 #include <sys/filio.h> 33911106dfSjm199354 #include <sys/types.h> 34911106dfSjm199354 #include <sys/socket.h> 35911106dfSjm199354 #include <sys/ioctl.h> 36911106dfSjm199354 #include <sys/param.h> 37911106dfSjm199354 #include <zone.h> 38911106dfSjm199354 #include <tsol/label.h> 39911106dfSjm199354 #include <string.h> 40911106dfSjm199354 #include <stdlib.h> 41911106dfSjm199354 #include <fcntl.h> 42911106dfSjm199354 #include <wait.h> 43911106dfSjm199354 #include <unistd.h> 44911106dfSjm199354 #include <getopt.h> 45911106dfSjm199354 #include <stdarg.h> 46911106dfSjm199354 #include <libscf.h> 47911106dfSjm199354 #include <signal.h> 48*8d7e4166Sjose borrego #include <atomic.h> 49911106dfSjm199354 #include <libintl.h> 50911106dfSjm199354 #include <netinet/in.h> 51911106dfSjm199354 #include <arpa/inet.h> 52911106dfSjm199354 #include <ctype.h> 53911106dfSjm199354 #include <pthread.h> 54911106dfSjm199354 #include <syslog.h> 55911106dfSjm199354 #include <locale.h> 56911106dfSjm199354 #include <pwd.h> 57911106dfSjm199354 #include <grp.h> 58911106dfSjm199354 #include <priv_utils.h> 59bfc848c6Sjm199354 #include <rctl.h> 60911106dfSjm199354 #include "vs_incl.h" 61911106dfSjm199354 62bfc848c6Sjm199354 #define VS_FILE_DESCRIPTORS 512 63bfc848c6Sjm199354 64911106dfSjm199354 static int vscand_fg = 0; /* daemon by default */ 65911106dfSjm199354 static vs_daemon_state_t vscand_state = VS_STATE_INIT; 66*8d7e4166Sjose borrego static volatile uint_t vscand_sigval = 0; 67*8d7e4166Sjose borrego static volatile uint_t vscand_n_refresh = 0; 68911106dfSjm199354 static int vscand_kdrv_fd = -1; 69911106dfSjm199354 static pthread_mutex_t vscand_cfg_mutex = PTHREAD_MUTEX_INITIALIZER; 70bfc848c6Sjm199354 static pthread_cond_t vscand_cfg_cv; 71bfc848c6Sjm199354 static pthread_t vscand_cfg_tid = 0; 72911106dfSjm199354 73911106dfSjm199354 /* virus log path */ 74911106dfSjm199354 static char vscand_vlog[MAXPATHLEN]; 75911106dfSjm199354 76911106dfSjm199354 /* user and group ids - default to 0 */ 77911106dfSjm199354 static uid_t root_uid = 0, daemon_uid = 0; 78911106dfSjm199354 static gid_t sys_gid = 0; 79911106dfSjm199354 80911106dfSjm199354 81911106dfSjm199354 /* local function prototypes */ 82911106dfSjm199354 static void vscand_sig_handler(int); 83911106dfSjm199354 static int vscand_parse_args(int, char **); 84911106dfSjm199354 static void vscand_get_uid_gid(); 85911106dfSjm199354 static int vscand_init_file(char *, uid_t, gid_t, mode_t); 86911106dfSjm199354 static void vscand_usage(char *); 87911106dfSjm199354 static int vscand_daemonize_init(void); 88911106dfSjm199354 static void vscand_daemonize_fini(int, int); 89911106dfSjm199354 static int vscand_init(void); 90911106dfSjm199354 static void vscand_fini(void); 91bfc848c6Sjm199354 static int vscand_cfg_init(void); 92bfc848c6Sjm199354 static void vscand_cfg_fini(void); 93bfc848c6Sjm199354 static void *vscand_cfg_handler(void *); 94911106dfSjm199354 static int vscand_configure(void); 95bfc848c6Sjm199354 static void vscand_dtrace_cfg(vs_props_all_t *); 96911106dfSjm199354 static int vscand_kernel_bind(void); 97911106dfSjm199354 static void vscand_kernel_unbind(void); 98911106dfSjm199354 static int vscand_kernel_enable(int); 99911106dfSjm199354 static void vscand_kernel_disable(void); 100911106dfSjm199354 static int vscand_kernel_config(vs_config_t *); 101bfc848c6Sjm199354 static int vscand_kernel_max_req(uint32_t *); 102911106dfSjm199354 static void vscand_error(const char *); 103911106dfSjm199354 static int vscand_get_viruslog(void); 104bfc848c6Sjm199354 static int vscand_set_resource_limits(void); 105911106dfSjm199354 106911106dfSjm199354 107911106dfSjm199354 /* 108911106dfSjm199354 * Enable libumem debugging by default on DEBUG builds. 109911106dfSjm199354 */ 110911106dfSjm199354 #ifdef DEBUG 111911106dfSjm199354 const char * 112911106dfSjm199354 _umem_debug_init(void) 113911106dfSjm199354 { 114911106dfSjm199354 return ("default,verbose"); /* $UMEM_DEBUG setting */ 115911106dfSjm199354 } 116911106dfSjm199354 117911106dfSjm199354 const char * 118911106dfSjm199354 _umem_logging_init(void) 119911106dfSjm199354 { 120911106dfSjm199354 return ("fail,contents"); /* $UMEM_LOGGING setting */ 121911106dfSjm199354 } 122911106dfSjm199354 #endif 123911106dfSjm199354 124911106dfSjm199354 125911106dfSjm199354 /* 126*8d7e4166Sjose borrego * vscand_sig_handler 127911106dfSjm199354 */ 128911106dfSjm199354 static void 129911106dfSjm199354 vscand_sig_handler(int sig) 130911106dfSjm199354 { 131911106dfSjm199354 if (vscand_sigval == 0) 132*8d7e4166Sjose borrego (void) atomic_swap_uint(&vscand_sigval, sig); 133*8d7e4166Sjose borrego 134*8d7e4166Sjose borrego if (sig == SIGHUP) 135*8d7e4166Sjose borrego atomic_inc_uint(&vscand_n_refresh); 136911106dfSjm199354 } 137911106dfSjm199354 138911106dfSjm199354 139911106dfSjm199354 /* 140911106dfSjm199354 * main 141911106dfSjm199354 * 142911106dfSjm199354 * main must return SMF return code (see smf_method (5)) if vscand 143911106dfSjm199354 * is invoked directly by smf (see manifest: vscan.xml) 144911106dfSjm199354 * Exit codes: SMF_EXIT_ERR_CONFIG - error 145911106dfSjm199354 * SMF_EXIT_ERR_FATAL - fatal error 146911106dfSjm199354 * SMF_EXIT_OK - success 147911106dfSjm199354 */ 148911106dfSjm199354 int 149911106dfSjm199354 main(int argc, char **argv) 150911106dfSjm199354 { 151911106dfSjm199354 int err_stat = 0, pfd = -1; 152911106dfSjm199354 sigset_t set; 153911106dfSjm199354 struct sigaction act; 154bfc848c6Sjm199354 int sigval; 155bfc848c6Sjm199354 156911106dfSjm199354 mode_t log_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP; 157911106dfSjm199354 mode_t door_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; 158911106dfSjm199354 159911106dfSjm199354 (void) setlocale(LC_ALL, ""); 160911106dfSjm199354 openlog("vscand", 0, LOG_DAEMON); 161911106dfSjm199354 162911106dfSjm199354 /* check if running in global zone; other zones not supported */ 163911106dfSjm199354 if (getzoneid() != GLOBAL_ZONEID) { 164911106dfSjm199354 vscand_error(gettext("non-global zone not supported")); 165911106dfSjm199354 exit(SMF_EXIT_ERR_FATAL); 166911106dfSjm199354 } 167911106dfSjm199354 168911106dfSjm199354 /* check for a Trusted Solaris environment; not supported */ 169911106dfSjm199354 if (is_system_labeled()) { 170911106dfSjm199354 vscand_error(gettext("Trusted Extensions not supported")); 171911106dfSjm199354 exit(SMF_EXIT_ERR_FATAL); 172911106dfSjm199354 } 173911106dfSjm199354 174911106dfSjm199354 /* Parse arguments */ 175911106dfSjm199354 if (vscand_parse_args(argc, argv) != 0) 176911106dfSjm199354 exit(SMF_EXIT_ERR_CONFIG); 177911106dfSjm199354 178911106dfSjm199354 vscand_get_uid_gid(); 179911106dfSjm199354 180911106dfSjm199354 /* 181911106dfSjm199354 * Initializetion of virus log and statistic door file 182911106dfSjm199354 * MUST be done BEFORE vscand_daemonize_init resets uid/gid. 183911106dfSjm199354 * Only root can create the files in /var/log and /var/run. 184911106dfSjm199354 */ 185911106dfSjm199354 if ((vscand_get_viruslog() != 0) || 186911106dfSjm199354 (vscand_vlog[0] == '\0') || 187911106dfSjm199354 (vscand_init_file(vscand_vlog, root_uid, sys_gid, log_mode) != 0)) { 188911106dfSjm199354 *vscand_vlog = 0; 189911106dfSjm199354 } 190911106dfSjm199354 191911106dfSjm199354 (void) vscand_init_file(VS_STATS_DOOR_NAME, 192911106dfSjm199354 daemon_uid, sys_gid, door_mode); 193911106dfSjm199354 194911106dfSjm199354 /* 195911106dfSjm199354 * Once we're done setting our global state up, set up signal handlers 196bfc848c6Sjm199354 * for ensuring orderly termination on SIGTERM. 197911106dfSjm199354 */ 198911106dfSjm199354 (void) sigfillset(&set); 199911106dfSjm199354 (void) sigdelset(&set, SIGABRT); /* always unblocked for ASSERT() */ 200911106dfSjm199354 201911106dfSjm199354 (void) sigfillset(&act.sa_mask); 202911106dfSjm199354 act.sa_handler = vscand_sig_handler; 203911106dfSjm199354 act.sa_flags = 0; 204911106dfSjm199354 205911106dfSjm199354 (void) sigaction(SIGTERM, &act, NULL); 206911106dfSjm199354 (void) sigaction(SIGHUP, &act, NULL); /* Refresh config */ 207911106dfSjm199354 (void) sigaction(SIGINT, &act, NULL); 208bfc848c6Sjm199354 (void) sigaction(SIGPIPE, &act, NULL); 209911106dfSjm199354 (void) sigdelset(&set, SIGTERM); 210911106dfSjm199354 (void) sigdelset(&set, SIGHUP); 211911106dfSjm199354 (void) sigdelset(&set, SIGINT); 212bfc848c6Sjm199354 (void) sigdelset(&set, SIGPIPE); 213911106dfSjm199354 214911106dfSjm199354 if (vscand_fg) { 215911106dfSjm199354 (void) sigdelset(&set, SIGTSTP); 216911106dfSjm199354 (void) sigdelset(&set, SIGTTIN); 217911106dfSjm199354 (void) sigdelset(&set, SIGTTOU); 218911106dfSjm199354 219911106dfSjm199354 if (vscand_init() != 0) { 220911106dfSjm199354 vscand_error(gettext("failed to initialize service")); 221911106dfSjm199354 exit(SMF_EXIT_ERR_CONFIG); 222911106dfSjm199354 } 223911106dfSjm199354 } else { 224911106dfSjm199354 /* 225911106dfSjm199354 * "pfd" is a pipe descriptor -- any fatal errors 226911106dfSjm199354 * during subsequent initialization of the child 227911106dfSjm199354 * process should be written to this pipe and the 228911106dfSjm199354 * parent will report this error as the exit status. 229911106dfSjm199354 */ 230911106dfSjm199354 pfd = vscand_daemonize_init(); 231911106dfSjm199354 232911106dfSjm199354 if (vscand_init() != 0) { 233911106dfSjm199354 vscand_error(gettext("failed to initialize service")); 234911106dfSjm199354 exit(SMF_EXIT_ERR_CONFIG); 235911106dfSjm199354 } 236911106dfSjm199354 237911106dfSjm199354 vscand_daemonize_fini(pfd, err_stat); 238911106dfSjm199354 } 239911106dfSjm199354 240911106dfSjm199354 vscand_state = VS_STATE_RUNNING; 241911106dfSjm199354 242911106dfSjm199354 /* Wait here until shutdown */ 243911106dfSjm199354 while (vscand_state == VS_STATE_RUNNING) { 244*8d7e4166Sjose borrego if (vscand_sigval == 0 && vscand_n_refresh == 0) 245911106dfSjm199354 (void) sigsuspend(&set); 246911106dfSjm199354 247*8d7e4166Sjose borrego sigval = atomic_swap_uint(&vscand_sigval, 0); 248bfc848c6Sjm199354 249bfc848c6Sjm199354 switch (sigval) { 250911106dfSjm199354 case 0: 251bfc848c6Sjm199354 case SIGPIPE: 252911106dfSjm199354 case SIGHUP: 253911106dfSjm199354 break; 254911106dfSjm199354 default: 255911106dfSjm199354 vscand_state = VS_STATE_SHUTDOWN; 256911106dfSjm199354 break; 257911106dfSjm199354 } 258*8d7e4166Sjose borrego 259*8d7e4166Sjose borrego if (atomic_swap_uint(&vscand_n_refresh, 0) != 0) 260*8d7e4166Sjose borrego (void) pthread_cond_signal(&vscand_cfg_cv); 261911106dfSjm199354 } 262911106dfSjm199354 263911106dfSjm199354 vscand_fini(); 264911106dfSjm199354 return (SMF_EXIT_OK); 265911106dfSjm199354 } 266911106dfSjm199354 267911106dfSjm199354 268911106dfSjm199354 /* 269bfc848c6Sjm199354 * vscand_parse_args 270911106dfSjm199354 * Routine to parse the arguments to the daemon program 271911106dfSjm199354 * 'f' argument runs process in the foreground instead of as a daemon 272911106dfSjm199354 */ 273911106dfSjm199354 int 274911106dfSjm199354 vscand_parse_args(int argc, char **argv) 275911106dfSjm199354 { 276911106dfSjm199354 int optchar; 277911106dfSjm199354 278911106dfSjm199354 while ((optchar = getopt(argc, argv, "f?")) != EOF) { 279911106dfSjm199354 switch (optchar) { 280911106dfSjm199354 case 'f': 281911106dfSjm199354 vscand_fg = 1; 282911106dfSjm199354 break; 283911106dfSjm199354 default: 284911106dfSjm199354 vscand_usage(argv[0]); 285911106dfSjm199354 return (-1); 286911106dfSjm199354 } 287911106dfSjm199354 } 288911106dfSjm199354 return (0); 289911106dfSjm199354 } 290911106dfSjm199354 291911106dfSjm199354 292911106dfSjm199354 /* 293911106dfSjm199354 * vscand_usage 294911106dfSjm199354 */ 295911106dfSjm199354 static void 296911106dfSjm199354 vscand_usage(char *progname) 297911106dfSjm199354 { 298911106dfSjm199354 char buf[128]; 299911106dfSjm199354 300911106dfSjm199354 (void) snprintf(buf, sizeof (buf), "%s %s [-f]", 301911106dfSjm199354 gettext("Usage"), progname); 302911106dfSjm199354 vscand_error(buf); 303911106dfSjm199354 304911106dfSjm199354 (void) snprintf(buf, sizeof (buf), "\t-f %s\n", 305911106dfSjm199354 gettext("run program in foreground")); 306911106dfSjm199354 vscand_error(buf); 307911106dfSjm199354 } 308911106dfSjm199354 309911106dfSjm199354 310911106dfSjm199354 /* 311911106dfSjm199354 * vscand_get_uid_gid 312911106dfSjm199354 * 313911106dfSjm199354 * failure to access a uid/gid results in the default (0) being used. 314911106dfSjm199354 */ 315911106dfSjm199354 static void 316911106dfSjm199354 vscand_get_uid_gid() 317911106dfSjm199354 { 318911106dfSjm199354 struct passwd *pwd; 319911106dfSjm199354 struct group *grp; 320911106dfSjm199354 321911106dfSjm199354 if ((pwd = getpwnam("root")) != NULL) 322911106dfSjm199354 root_uid = pwd->pw_uid; 323911106dfSjm199354 324911106dfSjm199354 if ((pwd = getpwnam("daemon")) != NULL) 325911106dfSjm199354 daemon_uid = pwd->pw_uid; 326911106dfSjm199354 327911106dfSjm199354 if ((grp = getgrnam("sys")) != NULL) 328911106dfSjm199354 sys_gid = grp->gr_gid; 329911106dfSjm199354 } 330911106dfSjm199354 331911106dfSjm199354 332911106dfSjm199354 /* 333911106dfSjm199354 * vscand_daemonize_init 334911106dfSjm199354 * 335911106dfSjm199354 * This function will fork off a child process, from which 336911106dfSjm199354 * only the child will return. 337911106dfSjm199354 */ 338911106dfSjm199354 static int 339911106dfSjm199354 vscand_daemonize_init(void) 340911106dfSjm199354 { 341911106dfSjm199354 int status, pfds[2]; 342911106dfSjm199354 sigset_t set, oset; 343911106dfSjm199354 pid_t pid; 344911106dfSjm199354 345911106dfSjm199354 /* 346911106dfSjm199354 * Reset process owner/group to daemon/sys. Root ownership is only 347911106dfSjm199354 * required to initialize virus log file in /var/log 348911106dfSjm199354 */ 349911106dfSjm199354 if (__init_daemon_priv(PU_RESETGROUPS | PU_LIMITPRIVS, 350911106dfSjm199354 daemon_uid, sys_gid, 351911106dfSjm199354 PRIV_PROC_AUDIT, PRIV_FILE_DAC_SEARCH, PRIV_FILE_DAC_READ, 352911106dfSjm199354 PRIV_FILE_FLAG_SET, NULL) != 0) { 353911106dfSjm199354 vscand_error(gettext("failed to initialize privileges")); 354911106dfSjm199354 _exit(SMF_EXIT_ERR_FATAL); 355911106dfSjm199354 } 356911106dfSjm199354 357911106dfSjm199354 /* 358911106dfSjm199354 * Block all signals prior to the fork and leave them blocked in the 359911106dfSjm199354 * parent so we don't get in a situation where the parent gets SIGINT 360911106dfSjm199354 * and returns non-zero exit status and the child is actually running. 361911106dfSjm199354 * In the child, restore the signal mask once we've done our setsid(). 362911106dfSjm199354 */ 363911106dfSjm199354 (void) sigfillset(&set); 364911106dfSjm199354 (void) sigdelset(&set, SIGABRT); 365911106dfSjm199354 (void) sigprocmask(SIG_BLOCK, &set, &oset); 366911106dfSjm199354 367911106dfSjm199354 if (pipe(pfds) == -1) { 368911106dfSjm199354 vscand_error(gettext("failed to create pipe for daemonize")); 369911106dfSjm199354 _exit(SMF_EXIT_ERR_FATAL); 370911106dfSjm199354 } 371911106dfSjm199354 372911106dfSjm199354 if ((pid = fork()) == -1) { 373911106dfSjm199354 vscand_error(gettext("failed to fork for daemonize")); 374911106dfSjm199354 _exit(SMF_EXIT_ERR_FATAL); 375911106dfSjm199354 } 376911106dfSjm199354 377911106dfSjm199354 /* 378911106dfSjm199354 * If we're the parent process, wait for either the child to send us 379911106dfSjm199354 * the appropriate exit status over the pipe or for the read to fail 380911106dfSjm199354 * (presumably with 0 for EOF if our child terminated abnormally). 381911106dfSjm199354 * If the read fails, exit with either the child's exit status if it 382911106dfSjm199354 * exited or with SMF_EXIT_ERR_FATAL if it died from a fatal signal. 383911106dfSjm199354 */ 384911106dfSjm199354 if (pid != 0) { 385911106dfSjm199354 (void) close(pfds[1]); 386911106dfSjm199354 387911106dfSjm199354 if (read(pfds[0], &status, sizeof (status)) == sizeof (status)) 388911106dfSjm199354 _exit(status); 389911106dfSjm199354 390911106dfSjm199354 if (waitpid(pid, &status, 0) == pid && WIFEXITED(status)) 391911106dfSjm199354 _exit(WEXITSTATUS(status)); 392911106dfSjm199354 393911106dfSjm199354 vscand_error(gettext("failed to daemonize")); 394911106dfSjm199354 _exit(SMF_EXIT_ERR_FATAL); 395911106dfSjm199354 } 396911106dfSjm199354 397911106dfSjm199354 398911106dfSjm199354 (void) setsid(); 399911106dfSjm199354 (void) sigprocmask(SIG_SETMASK, &oset, NULL); 400911106dfSjm199354 (void) chdir("/"); 401911106dfSjm199354 (void) umask(022); 402911106dfSjm199354 (void) close(pfds[0]); 403911106dfSjm199354 404911106dfSjm199354 return (pfds[1]); 405911106dfSjm199354 } 406911106dfSjm199354 407911106dfSjm199354 408911106dfSjm199354 /* 409911106dfSjm199354 * vscand_daemonize_fini 410911106dfSjm199354 * Now that we're running, if a pipe fd was specified, write an exit 411911106dfSjm199354 * status to it to indicate that our parent process can safely detach. 412911106dfSjm199354 */ 413911106dfSjm199354 static void 414911106dfSjm199354 vscand_daemonize_fini(int fd, int err_status) 415911106dfSjm199354 { 416911106dfSjm199354 if (fd >= 0) 417911106dfSjm199354 (void) write(fd, &err_status, sizeof (err_status)); 418911106dfSjm199354 419911106dfSjm199354 (void) close(fd); 420911106dfSjm199354 421911106dfSjm199354 /* Restore standard file descriptors */ 422911106dfSjm199354 if ((fd = open("/dev/null", O_RDWR)) >= 0) { 423911106dfSjm199354 (void) fcntl(fd, F_DUP2FD, STDIN_FILENO); 424911106dfSjm199354 (void) fcntl(fd, F_DUP2FD, STDOUT_FILENO); 425911106dfSjm199354 (void) fcntl(fd, F_DUP2FD, STDERR_FILENO); 426911106dfSjm199354 (void) close(fd); 427911106dfSjm199354 } 428911106dfSjm199354 429911106dfSjm199354 /* clear basic privileges not required by vscand */ 430911106dfSjm199354 __fini_daemon_priv(PRIV_PROC_FORK, PRIV_PROC_EXEC, PRIV_PROC_SESSION, 431911106dfSjm199354 PRIV_FILE_LINK_ANY, PRIV_PROC_INFO, (char *)NULL); 432911106dfSjm199354 } 433911106dfSjm199354 434911106dfSjm199354 435911106dfSjm199354 /* 436911106dfSjm199354 * vscand_init_file 437911106dfSjm199354 * 438911106dfSjm199354 * create specified file and set its uid, gid and mode 439911106dfSjm199354 */ 440911106dfSjm199354 static int 441bfc848c6Sjm199354 vscand_init_file(char *filepath, uid_t uid, gid_t gid, mode_t access_mode) 442911106dfSjm199354 { 443911106dfSjm199354 int fd, rc = 0; 444911106dfSjm199354 struct stat stat_buf; 445911106dfSjm199354 char buf[MAXPATHLEN]; 446911106dfSjm199354 447bfc848c6Sjm199354 if ((fd = open(filepath, O_RDONLY | O_CREAT, access_mode)) == -1) { 448911106dfSjm199354 rc = -1; 449bfc848c6Sjm199354 } else { 450bfc848c6Sjm199354 if (fstat(fd, &stat_buf) != 0) { 451911106dfSjm199354 rc = -1; 452bfc848c6Sjm199354 } else { 453bfc848c6Sjm199354 if ((stat_buf.st_mode & S_IAMB) != access_mode) { 454bfc848c6Sjm199354 if (fchmod(fd, access_mode) != 0) 455911106dfSjm199354 rc = -1; 456911106dfSjm199354 } 457911106dfSjm199354 458911106dfSjm199354 if ((stat_buf.st_uid != uid) || 459911106dfSjm199354 (stat_buf.st_gid != gid)) { 460911106dfSjm199354 if (fchown(fd, uid, gid) != 0) 461911106dfSjm199354 rc = -1; 462911106dfSjm199354 } 463911106dfSjm199354 } 464911106dfSjm199354 465911106dfSjm199354 (void) close(fd); 466911106dfSjm199354 } 467911106dfSjm199354 468911106dfSjm199354 if (rc == -1) { 469911106dfSjm199354 (void) snprintf(buf, MAXPATHLEN, "%s %s", 470911106dfSjm199354 gettext("Failed to initialize"), filepath); 471911106dfSjm199354 vscand_error(buf); 472911106dfSjm199354 } 473911106dfSjm199354 474911106dfSjm199354 return (rc); 475911106dfSjm199354 } 476911106dfSjm199354 477911106dfSjm199354 478911106dfSjm199354 /* 479911106dfSjm199354 * vscand_init 480911106dfSjm199354 * 481911106dfSjm199354 * There are some requirements on the order in which the daemon 482911106dfSjm199354 * initialization functions are called. 483911106dfSjm199354 * 484911106dfSjm199354 * - vscand_kernel_bind - bind to kernel module 485911106dfSjm199354 * - vs_eng_init populates vs_icap data and thus vs_icap_init MUST be 486911106dfSjm199354 * called before vs_eng_init 487911106dfSjm199354 * - vscand_configure - load the configuration 488911106dfSjm199354 * - vs_door_init - start vscan door server 489911106dfSjm199354 * - vscand_kernel_enable - enable scan requests from kernel 490911106dfSjm199354 */ 491911106dfSjm199354 static int 492911106dfSjm199354 vscand_init(void) 493911106dfSjm199354 { 494911106dfSjm199354 int door_fd = -1; 495bfc848c6Sjm199354 uint32_t max_req; 496911106dfSjm199354 497911106dfSjm199354 if (vscand_kernel_bind() < 0) 498911106dfSjm199354 return (-1); 499911106dfSjm199354 500bfc848c6Sjm199354 if (vscand_kernel_max_req(&max_req) == -1) 501bfc848c6Sjm199354 return (-1); 502bfc848c6Sjm199354 503bfc848c6Sjm199354 if (vs_svc_init(max_req) != 0) 504bfc848c6Sjm199354 return (-1); 505bfc848c6Sjm199354 506911106dfSjm199354 if (vs_stats_init() != 0) 507911106dfSjm199354 vscand_error( 508911106dfSjm199354 gettext("failed to initialize statistics interface")); 509911106dfSjm199354 510911106dfSjm199354 vs_icap_init(); 511911106dfSjm199354 vs_eng_init(); 512911106dfSjm199354 513bfc848c6Sjm199354 /* initialize configuration and handler thread */ 514bfc848c6Sjm199354 if (vscand_cfg_init() != 0) { 515911106dfSjm199354 vscand_error(gettext("failed to initialize configuration")); 516bfc848c6Sjm199354 vscand_fini(); 517911106dfSjm199354 return (-1); 518911106dfSjm199354 } 519911106dfSjm199354 520bfc848c6Sjm199354 (void) vscand_set_resource_limits(); 521bfc848c6Sjm199354 522911106dfSjm199354 if (((door_fd = vs_door_init()) < 0) || 523911106dfSjm199354 (vscand_kernel_enable(door_fd) < 0)) { 524911106dfSjm199354 vscand_fini(); 525911106dfSjm199354 return (-1); 526911106dfSjm199354 } 527911106dfSjm199354 528911106dfSjm199354 return (0); 529911106dfSjm199354 } 530911106dfSjm199354 531911106dfSjm199354 532911106dfSjm199354 /* 533911106dfSjm199354 * vscand_fini 534911106dfSjm199354 * 535911106dfSjm199354 * vscand_kernel_disable - should be called first to ensure that no 536911106dfSjm199354 * more scan requests are initiated from the kernel module 537bfc848c6Sjm199354 * vs_svc_terminate - terminate requests and wait for thread completion 538bfc848c6Sjm199354 * vs_xxx_fini - module cleanup routines 539911106dfSjm199354 * vscand_kernel_unbind - should be called last to tell the kernel module 540911106dfSjm199354 * that vscand is shutdown. 541911106dfSjm199354 */ 542911106dfSjm199354 static void 543911106dfSjm199354 vscand_fini(void) 544911106dfSjm199354 { 545911106dfSjm199354 vscand_kernel_disable(); 546911106dfSjm199354 547bfc848c6Sjm199354 /* terminate reconfiguration handler thread */ 548bfc848c6Sjm199354 vscand_cfg_fini(); 549bfc848c6Sjm199354 550bfc848c6Sjm199354 /* terminate requests and wait for completion */ 551bfc848c6Sjm199354 vs_svc_terminate(); 552bfc848c6Sjm199354 553bfc848c6Sjm199354 /* clean up */ 554911106dfSjm199354 vs_svc_fini(); 555911106dfSjm199354 vs_eng_fini(); 556911106dfSjm199354 vs_icap_fini(); 557911106dfSjm199354 vs_door_fini(); 558911106dfSjm199354 vs_stats_fini(); 559911106dfSjm199354 560911106dfSjm199354 vscand_kernel_unbind(); 561911106dfSjm199354 } 562911106dfSjm199354 563911106dfSjm199354 564911106dfSjm199354 /* 565bfc848c6Sjm199354 * vscand_cfg_init 566bfc848c6Sjm199354 * 567bfc848c6Sjm199354 * initialize configuration and reconfiguration handler thread 568bfc848c6Sjm199354 */ 569bfc848c6Sjm199354 static int 570bfc848c6Sjm199354 vscand_cfg_init(void) 571bfc848c6Sjm199354 { 572bfc848c6Sjm199354 int rc; 573bfc848c6Sjm199354 574bfc848c6Sjm199354 (void) pthread_cond_init(&vscand_cfg_cv, NULL); 575bfc848c6Sjm199354 576bfc848c6Sjm199354 (void) pthread_mutex_lock(&vscand_cfg_mutex); 577bfc848c6Sjm199354 rc = vscand_configure(); 578bfc848c6Sjm199354 (void) pthread_mutex_unlock(&vscand_cfg_mutex); 579bfc848c6Sjm199354 580bfc848c6Sjm199354 if (rc != 0) 581bfc848c6Sjm199354 return (-1); 582bfc848c6Sjm199354 583bfc848c6Sjm199354 if (pthread_create(&vscand_cfg_tid, NULL, vscand_cfg_handler, 0) != 0) { 584bfc848c6Sjm199354 vscand_cfg_tid = 0; 585bfc848c6Sjm199354 return (-1); 586bfc848c6Sjm199354 } 587bfc848c6Sjm199354 588bfc848c6Sjm199354 return (0); 589bfc848c6Sjm199354 } 590bfc848c6Sjm199354 591bfc848c6Sjm199354 592bfc848c6Sjm199354 /* 593bfc848c6Sjm199354 * vscand_cfg_fini 594bfc848c6Sjm199354 * 595bfc848c6Sjm199354 * terminate reconfiguration handler thread 596bfc848c6Sjm199354 */ 597bfc848c6Sjm199354 static void 598bfc848c6Sjm199354 vscand_cfg_fini() 599bfc848c6Sjm199354 { 600bfc848c6Sjm199354 if (vscand_cfg_tid != 0) { 601bfc848c6Sjm199354 (void) pthread_cond_signal(&vscand_cfg_cv); 602bfc848c6Sjm199354 (void) pthread_join(vscand_cfg_tid, NULL); 603bfc848c6Sjm199354 vscand_cfg_tid = 0; 604bfc848c6Sjm199354 } 605bfc848c6Sjm199354 (void) pthread_cond_destroy(&vscand_cfg_cv); 606bfc848c6Sjm199354 } 607bfc848c6Sjm199354 608bfc848c6Sjm199354 609bfc848c6Sjm199354 /* 610bfc848c6Sjm199354 * vscand_cfg_handler 611bfc848c6Sjm199354 * wait for reconfiguration event and reload configuration 612bfc848c6Sjm199354 * exit on VS_STATE_SHUTDOWN 613bfc848c6Sjm199354 */ 614bfc848c6Sjm199354 /*ARGSUSED*/ 615bfc848c6Sjm199354 static void * 616bfc848c6Sjm199354 vscand_cfg_handler(void *arg) 617bfc848c6Sjm199354 { 618bfc848c6Sjm199354 (void) pthread_mutex_lock(&vscand_cfg_mutex); 619bfc848c6Sjm199354 620bfc848c6Sjm199354 while (pthread_cond_wait(&vscand_cfg_cv, &vscand_cfg_mutex) == 0) { 621bfc848c6Sjm199354 if (vscand_state == VS_STATE_SHUTDOWN) 622bfc848c6Sjm199354 break; 623bfc848c6Sjm199354 624bfc848c6Sjm199354 (void) vscand_configure(); 625bfc848c6Sjm199354 } 626bfc848c6Sjm199354 627bfc848c6Sjm199354 (void) pthread_mutex_unlock(&vscand_cfg_mutex); 628bfc848c6Sjm199354 629bfc848c6Sjm199354 return (NULL); 630bfc848c6Sjm199354 } 631bfc848c6Sjm199354 632bfc848c6Sjm199354 633bfc848c6Sjm199354 /* 634911106dfSjm199354 * vscand_configure 635911106dfSjm199354 */ 636911106dfSjm199354 static int 637911106dfSjm199354 vscand_configure(void) 638911106dfSjm199354 { 639911106dfSjm199354 uint32_t len; 640911106dfSjm199354 vs_config_t kconfig; 641911106dfSjm199354 vs_props_all_t config; 642911106dfSjm199354 643911106dfSjm199354 (void) memset(&config, 0, sizeof (vs_props_all_t)); 644911106dfSjm199354 if (vs_props_get_all(&config) != VS_ERR_NONE) { 645911106dfSjm199354 vscand_error(gettext("configuration data error")); 646911106dfSjm199354 return (-1); 647911106dfSjm199354 } 648911106dfSjm199354 649911106dfSjm199354 (void) memset(&kconfig, 0, sizeof (vs_config_t)); 650911106dfSjm199354 len = sizeof (kconfig.vsc_types); 651911106dfSjm199354 if (vs_parse_types(config.va_props.vp_types, 652911106dfSjm199354 kconfig.vsc_types, &len) != 0) { 653911106dfSjm199354 vscand_error(gettext("configuration data error - types")); 654911106dfSjm199354 return (-1); 655911106dfSjm199354 } 656911106dfSjm199354 kconfig.vsc_types_len = len; 657911106dfSjm199354 658911106dfSjm199354 /* Convert the maxfsize string from the configuration into bytes */ 659911106dfSjm199354 if (vs_strtonum(config.va_props.vp_maxsize, 660911106dfSjm199354 &kconfig.vsc_max_size) != 0) { 661911106dfSjm199354 vscand_error(gettext("configuration data error - max-size")); 662911106dfSjm199354 return (-1); 663911106dfSjm199354 } 664911106dfSjm199354 kconfig.vsc_allow = config.va_props.vp_maxsize_action ? 1LL : 0LL; 665911106dfSjm199354 666911106dfSjm199354 /* Send configuration update to kernel */ 667911106dfSjm199354 if (vscand_kernel_config(&kconfig) != 0) { 668911106dfSjm199354 return (-1); 669911106dfSjm199354 } 670911106dfSjm199354 671bfc848c6Sjm199354 /* dtrace the configuration data */ 672bfc848c6Sjm199354 vscand_dtrace_cfg(&config); 673911106dfSjm199354 674bfc848c6Sjm199354 /* propagate configuration changes */ 675bfc848c6Sjm199354 vs_eng_config(&config); 676911106dfSjm199354 vs_stats_config(&config); 677911106dfSjm199354 678911106dfSjm199354 return (0); 679911106dfSjm199354 } 680911106dfSjm199354 681911106dfSjm199354 682911106dfSjm199354 /* 683911106dfSjm199354 * vscand_get_state 684911106dfSjm199354 */ 685911106dfSjm199354 vs_daemon_state_t 686911106dfSjm199354 vscand_get_state(void) 687911106dfSjm199354 { 688911106dfSjm199354 return (vscand_state); 689911106dfSjm199354 } 690911106dfSjm199354 691911106dfSjm199354 692911106dfSjm199354 /* 693911106dfSjm199354 * vscand_get_viruslog 694911106dfSjm199354 */ 695911106dfSjm199354 static int 696911106dfSjm199354 vscand_get_viruslog() 697911106dfSjm199354 { 698911106dfSjm199354 vs_props_t props; 699911106dfSjm199354 uint64_t propids; 700911106dfSjm199354 int rc; 701911106dfSjm199354 702911106dfSjm199354 propids = VS_PROPID_VLOG; 703911106dfSjm199354 if ((rc = vs_props_get(&props, propids)) != VS_ERR_NONE) { 704911106dfSjm199354 vscand_error(vs_strerror(rc)); 705911106dfSjm199354 return (-1); 706911106dfSjm199354 } 707911106dfSjm199354 708911106dfSjm199354 (void) strlcpy(vscand_vlog, props.vp_vlog, sizeof (vscand_vlog)); 709911106dfSjm199354 return (0); 710911106dfSjm199354 } 711911106dfSjm199354 712911106dfSjm199354 713911106dfSjm199354 /* 714911106dfSjm199354 * vscand_viruslog 715911106dfSjm199354 */ 716911106dfSjm199354 char * 717911106dfSjm199354 vscand_viruslog(void) 718911106dfSjm199354 { 719911106dfSjm199354 if (vscand_vlog[0] == '\0') 720911106dfSjm199354 return (NULL); 721911106dfSjm199354 722911106dfSjm199354 return (vscand_vlog); 723911106dfSjm199354 } 724911106dfSjm199354 725911106dfSjm199354 726911106dfSjm199354 /* 727911106dfSjm199354 * vscand_kernel_bind 728911106dfSjm199354 */ 729911106dfSjm199354 static int 730911106dfSjm199354 vscand_kernel_bind(void) 731911106dfSjm199354 { 732911106dfSjm199354 char devname[MAXPATHLEN]; 733911106dfSjm199354 int inst = 0; 734911106dfSjm199354 735911106dfSjm199354 (void) snprintf(devname, MAXPATHLEN, "%s%d", VS_DRV_PATH, inst); 736911106dfSjm199354 737911106dfSjm199354 if ((vscand_kdrv_fd = open(devname, O_RDONLY)) < 0) { 738911106dfSjm199354 vscand_error(gettext("failed to bind to kernel")); 739911106dfSjm199354 return (-1); 740911106dfSjm199354 } 741911106dfSjm199354 742911106dfSjm199354 return (0); 743911106dfSjm199354 } 744911106dfSjm199354 745911106dfSjm199354 746911106dfSjm199354 /* 747911106dfSjm199354 * vscand_kernel_unbind 748911106dfSjm199354 */ 749911106dfSjm199354 static void 750911106dfSjm199354 vscand_kernel_unbind(void) 751911106dfSjm199354 { 752911106dfSjm199354 if (vscand_kdrv_fd >= 0) 753911106dfSjm199354 (void) close(vscand_kdrv_fd); 754911106dfSjm199354 } 755911106dfSjm199354 756911106dfSjm199354 757911106dfSjm199354 /* 758911106dfSjm199354 * vscand_kernel_enable 759911106dfSjm199354 */ 760911106dfSjm199354 static int 761911106dfSjm199354 vscand_kernel_enable(int door_fd) 762911106dfSjm199354 { 763bfc848c6Sjm199354 if (ioctl(vscand_kdrv_fd, VS_IOCTL_ENABLE, door_fd) < 0) { 764911106dfSjm199354 vscand_error(gettext("failed to bind to kernel")); 765911106dfSjm199354 (void) close(vscand_kdrv_fd); 766911106dfSjm199354 vscand_kdrv_fd = -1; 767911106dfSjm199354 return (-1); 768911106dfSjm199354 } 769911106dfSjm199354 return (0); 770911106dfSjm199354 } 771911106dfSjm199354 772911106dfSjm199354 773911106dfSjm199354 /* 774911106dfSjm199354 * vscand_kernel_disable 775911106dfSjm199354 */ 776911106dfSjm199354 static void 777911106dfSjm199354 vscand_kernel_disable() 778911106dfSjm199354 { 779911106dfSjm199354 if (vscand_kdrv_fd >= 0) 780bfc848c6Sjm199354 (void) ioctl(vscand_kdrv_fd, VS_IOCTL_DISABLE); 781911106dfSjm199354 } 782911106dfSjm199354 783911106dfSjm199354 784911106dfSjm199354 /* 785911106dfSjm199354 * vscand_kernel_config 786911106dfSjm199354 */ 787911106dfSjm199354 int 788911106dfSjm199354 vscand_kernel_config(vs_config_t *conf) 789911106dfSjm199354 { 790bfc848c6Sjm199354 if ((vscand_kdrv_fd < 0) || 791bfc848c6Sjm199354 (ioctl(vscand_kdrv_fd, VS_IOCTL_CONFIG, conf) < 0)) { 792911106dfSjm199354 vscand_error(gettext("failed to send config to kernel")); 793911106dfSjm199354 return (-1); 794911106dfSjm199354 } 795911106dfSjm199354 796911106dfSjm199354 return (0); 797911106dfSjm199354 } 798911106dfSjm199354 799911106dfSjm199354 800911106dfSjm199354 /* 801bfc848c6Sjm199354 * vscand_kernel_result 802bfc848c6Sjm199354 */ 803bfc848c6Sjm199354 int 804bfc848c6Sjm199354 vscand_kernel_result(vs_scan_rsp_t *scan_rsp) 805bfc848c6Sjm199354 { 806bfc848c6Sjm199354 if ((vscand_kdrv_fd < 0) || 807bfc848c6Sjm199354 (ioctl(vscand_kdrv_fd, VS_IOCTL_RESULT, scan_rsp) < 0)) { 808bfc848c6Sjm199354 vscand_error(gettext("failed to send result to kernel")); 809bfc848c6Sjm199354 return (-1); 810bfc848c6Sjm199354 } 811bfc848c6Sjm199354 812bfc848c6Sjm199354 return (0); 813bfc848c6Sjm199354 } 814bfc848c6Sjm199354 815bfc848c6Sjm199354 816bfc848c6Sjm199354 /* 817bfc848c6Sjm199354 * vscand_kernel_max_req 818bfc848c6Sjm199354 */ 819bfc848c6Sjm199354 int 820bfc848c6Sjm199354 vscand_kernel_max_req(uint32_t *max_req) 821bfc848c6Sjm199354 { 822bfc848c6Sjm199354 if ((vscand_kdrv_fd < 0) || 823bfc848c6Sjm199354 (ioctl(vscand_kdrv_fd, VS_IOCTL_MAX_REQ, max_req) < 0)) { 824bfc848c6Sjm199354 vscand_error(gettext("failed to get config data from kernel")); 825bfc848c6Sjm199354 return (-1); 826bfc848c6Sjm199354 } 827bfc848c6Sjm199354 828bfc848c6Sjm199354 return (0); 829bfc848c6Sjm199354 } 830bfc848c6Sjm199354 831bfc848c6Sjm199354 832bfc848c6Sjm199354 /* 833bfc848c6Sjm199354 * vscand_set_resource_limits 834bfc848c6Sjm199354 * 835bfc848c6Sjm199354 * If the process's max file descriptor limit is less than 836bfc848c6Sjm199354 * VS_FILE_DESCRIPTORS, increae it to VS_FILE_DESCRIPTORS. 837bfc848c6Sjm199354 */ 838bfc848c6Sjm199354 static int 839bfc848c6Sjm199354 vscand_set_resource_limits(void) 840bfc848c6Sjm199354 { 841bfc848c6Sjm199354 int rc = -1; 842bfc848c6Sjm199354 rctlblk_t *rblk; 843bfc848c6Sjm199354 char *limit = "process.max-file-descriptor"; 844bfc848c6Sjm199354 845bfc848c6Sjm199354 rblk = (rctlblk_t *)malloc(rctlblk_size()); 846bfc848c6Sjm199354 847bfc848c6Sjm199354 if (rblk != NULL) { 848bfc848c6Sjm199354 rc = getrctl(limit, NULL, rblk, 0); 849bfc848c6Sjm199354 if ((rc == 0) && 850bfc848c6Sjm199354 (rctlblk_get_value(rblk) < VS_FILE_DESCRIPTORS)) { 851bfc848c6Sjm199354 rctlblk_set_value(rblk, VS_FILE_DESCRIPTORS); 852bfc848c6Sjm199354 rc = setrctl(limit, NULL, rblk, 0); 853bfc848c6Sjm199354 } 854bfc848c6Sjm199354 (void) free(rblk); 855bfc848c6Sjm199354 } 856bfc848c6Sjm199354 857bfc848c6Sjm199354 return (rc); 858bfc848c6Sjm199354 } 859bfc848c6Sjm199354 860bfc848c6Sjm199354 861bfc848c6Sjm199354 /* 862911106dfSjm199354 * vscand_error 863911106dfSjm199354 */ 864911106dfSjm199354 static void 865911106dfSjm199354 vscand_error(const char *errmsg) 866911106dfSjm199354 { 867911106dfSjm199354 (void) fprintf(stderr, "vscand: %s", errmsg); 868911106dfSjm199354 syslog(LOG_ERR, "%s\n", errmsg); 869911106dfSjm199354 } 870bfc848c6Sjm199354 871bfc848c6Sjm199354 872bfc848c6Sjm199354 /* 873bfc848c6Sjm199354 * vscand_dtrace_cfg 874bfc848c6Sjm199354 * vscand_dtrace_gen 875bfc848c6Sjm199354 * vscand_dtrace_eng 876bfc848c6Sjm199354 * 877bfc848c6Sjm199354 * Support for dtracing vscand configuration when processing 878bfc848c6Sjm199354 * a reconfiguration event (SIGHUP) 879bfc848c6Sjm199354 */ 880bfc848c6Sjm199354 /*ARGSUSED*/ 881bfc848c6Sjm199354 static void 882bfc848c6Sjm199354 vscand_dtrace_eng(char *id, boolean_t enable, char *host, int port, int conn) 883bfc848c6Sjm199354 { 884bfc848c6Sjm199354 } 885bfc848c6Sjm199354 /*ARGSUSED*/ 886bfc848c6Sjm199354 static void 887bfc848c6Sjm199354 vscand_dtrace_gen(char *size, boolean_t action, char *types, char *log) 888bfc848c6Sjm199354 { 889bfc848c6Sjm199354 } 890bfc848c6Sjm199354 static void 891bfc848c6Sjm199354 vscand_dtrace_cfg(vs_props_all_t *config) 892bfc848c6Sjm199354 { 893bfc848c6Sjm199354 int i; 894bfc848c6Sjm199354 895bfc848c6Sjm199354 vscand_dtrace_gen(config->va_props.vp_maxsize, 896bfc848c6Sjm199354 config->va_props.vp_maxsize_action, 897bfc848c6Sjm199354 config->va_props.vp_types, 898bfc848c6Sjm199354 config->va_props.vp_vlog); 899bfc848c6Sjm199354 900bfc848c6Sjm199354 for (i = 0; i < VS_SE_MAX; i++) { 901bfc848c6Sjm199354 if (config->va_se[i].vep_engid[0] != 0) 902bfc848c6Sjm199354 vscand_dtrace_eng(config->va_se[i].vep_engid, 903bfc848c6Sjm199354 config->va_se[i].vep_enable, 904bfc848c6Sjm199354 config->va_se[i].vep_host, 905bfc848c6Sjm199354 config->va_se[i].vep_port, 906bfc848c6Sjm199354 config->va_se[i].vep_maxconn); 907bfc848c6Sjm199354 } 908bfc848c6Sjm199354 } 909