/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* vscand Daemon Program
*/
#include <stdio.h>
#include <zone.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <wait.h>
#include <unistd.h>
#include <getopt.h>
#include <stdarg.h>
#include <libscf.h>
#include <signal.h>
#include <atomic.h>
#include <libintl.h>
#include <ctype.h>
#include <pthread.h>
#include <syslog.h>
#include <locale.h>
#include <pwd.h>
#include <grp.h>
#include <priv_utils.h>
#include <rctl.h>
#include "vs_incl.h"
/* virus log path */
/* user and group ids - default to 0 */
/* local function prototypes */
static void vscand_sig_handler(int);
static int vscand_parse_args(int, char **);
static void vscand_get_uid_gid();
static void vscand_usage(char *);
static int vscand_daemonize_init(void);
static void vscand_daemonize_fini(int, int);
static int vscand_init(void);
static void vscand_fini(void);
static int vscand_cfg_init(void);
static void vscand_cfg_fini(void);
static void *vscand_cfg_handler(void *);
static int vscand_configure(void);
static void vscand_dtrace_cfg(vs_props_all_t *);
static int vscand_kernel_bind(void);
static void vscand_kernel_unbind(void);
static int vscand_kernel_enable(int);
static void vscand_kernel_disable(void);
static int vscand_kernel_config(vs_config_t *);
static int vscand_kernel_max_req(uint32_t *);
static void vscand_error(const char *);
static int vscand_get_viruslog(void);
static int vscand_set_resource_limits(void);
/*
* Enable libumem debugging by default on DEBUG builds.
*/
#ifdef DEBUG
const char *
_umem_debug_init(void)
{
return ("default,verbose"); /* $UMEM_DEBUG setting */
}
const char *
_umem_logging_init(void)
{
return ("fail,contents"); /* $UMEM_LOGGING setting */
}
#endif
/*
* vscand_sig_handler
*/
static void
{
if (vscand_sigval == 0)
}
/*
* main
*
* main must return SMF return code (see smf_method (5)) if vscand
* is invoked directly by smf (see manifest: vscan.xml)
* Exit codes: SMF_EXIT_ERR_CONFIG - error
* SMF_EXIT_ERR_FATAL - fatal error
* SMF_EXIT_OK - success
*/
int
{
int sigval;
/* check if running in global zone; other zones not supported */
if (getzoneid() != GLOBAL_ZONEID) {
}
/* check for a Trusted Solaris environment; not supported */
if (is_system_labeled()) {
}
/* Parse arguments */
/*
* Initializetion of virus log and statistic door file
*/
if ((vscand_get_viruslog() != 0) ||
(vscand_vlog[0] == '\0') ||
*vscand_vlog = 0;
}
(void) vscand_init_file(VS_STATS_DOOR_NAME,
/*
* Once we're done setting our global state up, set up signal handlers
* for ensuring orderly termination on SIGTERM.
*/
(void) sigfillset(&set);
if (vscand_fg) {
if (vscand_init() != 0) {
}
} else {
/*
* "pfd" is a pipe descriptor -- any fatal errors
* during subsequent initialization of the child
* process should be written to this pipe and the
* parent will report this error as the exit status.
*/
pfd = vscand_daemonize_init();
if (vscand_init() != 0) {
}
}
/* Wait here until shutdown */
while (vscand_state == VS_STATE_RUNNING) {
if (vscand_sigval == 0 && vscand_n_refresh == 0)
(void) sigsuspend(&set);
switch (sigval) {
case 0:
case SIGPIPE:
case SIGHUP:
break;
default:
break;
}
if (atomic_swap_uint(&vscand_n_refresh, 0) != 0)
(void) pthread_cond_signal(&vscand_cfg_cv);
}
vscand_fini();
return (SMF_EXIT_OK);
}
/*
* vscand_parse_args
* Routine to parse the arguments to the daemon program
* 'f' argument runs process in the foreground instead of as a daemon
*/
int
{
int optchar;
switch (optchar) {
case 'f':
vscand_fg = 1;
break;
default:
vscand_usage(argv[0]);
return (-1);
}
}
return (0);
}
/*
* vscand_usage
*/
static void
{
gettext("run program in foreground"));
}
/*
* vscand_get_uid_gid
*
*/
static void
{
}
/*
* vscand_daemonize_init
*
* This function will fork off a child process, from which
* only the child will return.
*/
static int
vscand_daemonize_init(void)
{
/*
*/
PRIV_FILE_FLAG_SET, NULL) != 0) {
}
/*
* Block all signals prior to the fork and leave them blocked in the
* parent so we don't get in a situation where the parent gets SIGINT
* and returns non-zero exit status and the child is actually running.
* In the child, restore the signal mask once we've done our setsid().
*/
(void) sigfillset(&set);
}
}
/*
* If we're the parent process, wait for either the child to send us
* the appropriate exit status over the pipe or for the read to fail
* (presumably with 0 for EOF if our child terminated abnormally).
* If the read fails, exit with either the child's exit status if it
* exited or with SMF_EXIT_ERR_FATAL if it died from a fatal signal.
*/
if (pid != 0) {
}
(void) setsid();
(void) chdir("/");
(void) umask(022);
return (pfds[1]);
}
/*
* vscand_daemonize_fini
* Now that we're running, if a pipe fd was specified, write an exit
* status to it to indicate that our parent process can safely detach.
*/
static void
{
if (fd >= 0)
/* Restore standard file descriptors */
}
/* clear basic privileges not required by vscand */
}
/*
* vscand_init_file
*
* create specified file and set its uid, gid and mode
*/
static int
{
rc = -1;
} else {
rc = -1;
} else {
rc = -1;
}
rc = -1;
}
}
}
if (rc == -1) {
}
return (rc);
}
/*
* vscand_init
*
* There are some requirements on the order in which the daemon
* initialization functions are called.
*
* - vscand_kernel_bind - bind to kernel module
* - vs_eng_init populates vs_icap data and thus vs_icap_init MUST be
* called before vs_eng_init
* - vscand_configure - load the configuration
* - vs_door_init - start vscan door server
* - vscand_kernel_enable - enable scan requests from kernel
*/
static int
vscand_init(void)
{
if (vscand_kernel_bind() < 0)
return (-1);
return (-1);
if (vs_svc_init(max_req) != 0)
return (-1);
if (vs_stats_init() != 0)
gettext("failed to initialize statistics interface"));
vs_icap_init();
vs_eng_init();
/* initialize configuration and handler thread */
if (vscand_cfg_init() != 0) {
vscand_fini();
return (-1);
}
(void) vscand_set_resource_limits();
if (((door_fd = vs_door_init()) < 0) ||
(vscand_kernel_enable(door_fd) < 0)) {
vscand_fini();
return (-1);
}
return (0);
}
/*
* vscand_fini
*
* vscand_kernel_disable - should be called first to ensure that no
* more scan requests are initiated from the kernel module
* vs_svc_terminate - terminate requests and wait for thread completion
* vs_xxx_fini - module cleanup routines
* vscand_kernel_unbind - should be called last to tell the kernel module
* that vscand is shutdown.
*/
static void
vscand_fini(void)
{
/* terminate reconfiguration handler thread */
/* terminate requests and wait for completion */
/* clean up */
vs_svc_fini();
vs_eng_fini();
vs_icap_fini();
vs_door_fini();
}
/*
* vscand_cfg_init
*
* initialize configuration and reconfiguration handler thread
*/
static int
vscand_cfg_init(void)
{
int rc;
(void) pthread_mutex_lock(&vscand_cfg_mutex);
rc = vscand_configure();
(void) pthread_mutex_unlock(&vscand_cfg_mutex);
if (rc != 0)
return (-1);
vscand_cfg_tid = 0;
return (-1);
}
return (0);
}
/*
* vscand_cfg_fini
*
* terminate reconfiguration handler thread
*/
static void
{
if (vscand_cfg_tid != 0) {
(void) pthread_cond_signal(&vscand_cfg_cv);
vscand_cfg_tid = 0;
}
(void) pthread_cond_destroy(&vscand_cfg_cv);
}
/*
* vscand_cfg_handler
* wait for reconfiguration event and reload configuration
* exit on VS_STATE_SHUTDOWN
*/
/*ARGSUSED*/
static void *
{
(void) pthread_mutex_lock(&vscand_cfg_mutex);
if (vscand_state == VS_STATE_SHUTDOWN)
break;
(void) vscand_configure();
}
(void) pthread_mutex_unlock(&vscand_cfg_mutex);
return (NULL);
}
/*
* vscand_configure
*/
static int
vscand_configure(void)
{
return (-1);
}
return (-1);
}
/* Convert the maxfsize string from the configuration into bytes */
&kconfig.vsc_max_size) != 0) {
return (-1);
}
/* Send configuration update to kernel */
if (vscand_kernel_config(&kconfig) != 0) {
return (-1);
}
/* dtrace the configuration data */
/* propagate configuration changes */
return (0);
}
/*
* vscand_get_state
*/
vscand_get_state(void)
{
return (vscand_state);
}
/*
* vscand_get_viruslog
*/
static int
{
int rc;
return (-1);
}
return (0);
}
/*
* vscand_viruslog
*/
char *
vscand_viruslog(void)
{
if (vscand_vlog[0] == '\0')
return (NULL);
return (vscand_vlog);
}
/*
* vscand_kernel_bind
*/
static int
vscand_kernel_bind(void)
{
int inst = 0;
return (-1);
}
return (0);
}
/*
* vscand_kernel_unbind
*/
static void
vscand_kernel_unbind(void)
{
if (vscand_kdrv_fd >= 0)
(void) close(vscand_kdrv_fd);
}
/*
* vscand_kernel_enable
*/
static int
{
(void) close(vscand_kdrv_fd);
vscand_kdrv_fd = -1;
return (-1);
}
return (0);
}
/*
* vscand_kernel_disable
*/
static void
{
if (vscand_kdrv_fd >= 0)
}
/*
* vscand_kernel_config
*/
int
{
if ((vscand_kdrv_fd < 0) ||
return (-1);
}
return (0);
}
/*
* vscand_kernel_result
*/
int
{
if ((vscand_kdrv_fd < 0) ||
return (-1);
}
return (0);
}
/*
* vscand_kernel_max_req
*/
int
{
if ((vscand_kdrv_fd < 0) ||
return (-1);
}
return (0);
}
/*
* vscand_set_resource_limits
*
* If the process's max file descriptor limit is less than
* VS_FILE_DESCRIPTORS, increae it to VS_FILE_DESCRIPTORS.
*/
static int
{
if ((rc == 0) &&
}
}
return (rc);
}
/*
* vscand_error
*/
static void
{
}
/*
* vscand_dtrace_cfg
* vscand_dtrace_gen
* vscand_dtrace_eng
*
* Support for dtracing vscand configuration when processing
* a reconfiguration event (SIGHUP)
*/
/*ARGSUSED*/
static void
{
}
/*ARGSUSED*/
static void
{
}
static void
{
int i;
for (i = 0; i < VS_SE_MAX; i++) {
}
}