xref: /onnv-gate/usr/src/cmd/cmd-inet/usr.lib/ilbd/ilbd_main.c (revision 12424:15132603c9ad)
110946SSangeeta.Misra@Sun.COM /*
210946SSangeeta.Misra@Sun.COM  * CDDL HEADER START
310946SSangeeta.Misra@Sun.COM  *
410946SSangeeta.Misra@Sun.COM  * The contents of this file are subject to the terms of the
510946SSangeeta.Misra@Sun.COM  * Common Development and Distribution License (the "License").
610946SSangeeta.Misra@Sun.COM  * You may not use this file except in compliance with the License.
710946SSangeeta.Misra@Sun.COM  *
810946SSangeeta.Misra@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
910946SSangeeta.Misra@Sun.COM  * or http://www.opensolaris.org/os/licensing.
1010946SSangeeta.Misra@Sun.COM  * See the License for the specific language governing permissions
1110946SSangeeta.Misra@Sun.COM  * and limitations under the License.
1210946SSangeeta.Misra@Sun.COM  *
1310946SSangeeta.Misra@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
1410946SSangeeta.Misra@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1510946SSangeeta.Misra@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
1610946SSangeeta.Misra@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
1710946SSangeeta.Misra@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
1810946SSangeeta.Misra@Sun.COM  *
1910946SSangeeta.Misra@Sun.COM  * CDDL HEADER END
2010946SSangeeta.Misra@Sun.COM  */
2110946SSangeeta.Misra@Sun.COM 
2210946SSangeeta.Misra@Sun.COM /*
23*12424SSangeeta.Misra@Sun.COM  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
2410946SSangeeta.Misra@Sun.COM  */
2510946SSangeeta.Misra@Sun.COM 
2610946SSangeeta.Misra@Sun.COM /*
2710946SSangeeta.Misra@Sun.COM  * The core of ilbd daemon is a single-threaded event loop using
2810946SSangeeta.Misra@Sun.COM  * event completion framework; it receives requests from client using
2910946SSangeeta.Misra@Sun.COM  * the libilb functions, handles timeouts, initiates health checks, and
3010946SSangeeta.Misra@Sun.COM  * populates the kernel state.
3110946SSangeeta.Misra@Sun.COM  *
3210946SSangeeta.Misra@Sun.COM  * The daemon has the following privileges (in addition to the basic ones):
3310946SSangeeta.Misra@Sun.COM  *
3410946SSangeeta.Misra@Sun.COM  * 	PRIV_PROC_OWNER, PRIV_NET_ICMPACCESS,
3510946SSangeeta.Misra@Sun.COM  *	PRIV_SYS_IP_CONFIG, PRIV_PROC_AUDIT
3610946SSangeeta.Misra@Sun.COM  *
3710946SSangeeta.Misra@Sun.COM  * The aforementioned  privileges will be specified in the SMF manifest.
3810946SSangeeta.Misra@Sun.COM  *
3910946SSangeeta.Misra@Sun.COM  * AF_UNIX socket is used for IPC between libilb and this daemon as
4010946SSangeeta.Misra@Sun.COM  * both processes will run on the same machine.
4110946SSangeeta.Misra@Sun.COM  *
4210946SSangeeta.Misra@Sun.COM  * To do health check, the daemon will create a timer for every health
4310946SSangeeta.Misra@Sun.COM  * check probe. Each of these timers will be  associated with the
4410946SSangeeta.Misra@Sun.COM  * event port. When a timer goes off, the daemon will initiate a
4510946SSangeeta.Misra@Sun.COM  * pipe to a separate process to execute the specific health check
4610946SSangeeta.Misra@Sun.COM  * probe. This new process will run with the same user-id as that of
4710946SSangeeta.Misra@Sun.COM  * ilbd daemon and will inherit all the privileges from the ilbd
4810946SSangeeta.Misra@Sun.COM  * daemon parent process except the following:
4910946SSangeeta.Misra@Sun.COM  *
5010946SSangeeta.Misra@Sun.COM  * PRIV_PROC_OWNER, PRIV_PROC_AUDIT
5110946SSangeeta.Misra@Sun.COM  *
5210946SSangeeta.Misra@Sun.COM  * All health checks, will be implemented as external methods
5310946SSangeeta.Misra@Sun.COM  * (binary or script). The following arguments will be passed
5410946SSangeeta.Misra@Sun.COM  * to external methods:
5510946SSangeeta.Misra@Sun.COM  *
5610946SSangeeta.Misra@Sun.COM  *	$1	VIP (literal IPv4 or IPv6 address)
5710946SSangeeta.Misra@Sun.COM  *	$2	Server IP (literal IPv4 or IPv6 address)
5810946SSangeeta.Misra@Sun.COM  *	$3	Protocol (UDP, TCP as a string)
5910946SSangeeta.Misra@Sun.COM  *	$4	The load balance mode, "DSR", "NAT", "HALF_NAT"
6010946SSangeeta.Misra@Sun.COM  *	$5	Numeric port range
6110946SSangeeta.Misra@Sun.COM  *	$6	maximum time (in seconds) the method
6210946SSangeeta.Misra@Sun.COM  * should wait before returning failure. If the method runs for
6310946SSangeeta.Misra@Sun.COM  * longer, it may be killed, and the test considered failed.
6410946SSangeeta.Misra@Sun.COM  *
6510946SSangeeta.Misra@Sun.COM  * Upon success, a health check method should print the RTT to the
6610946SSangeeta.Misra@Sun.COM  * it finds to its STDOUT for ilbd to consume.  The implicit unit
6710946SSangeeta.Misra@Sun.COM  * is microseconds but only the number needs to be printed.  If it
6810946SSangeeta.Misra@Sun.COM  * cannot find the RTT, it should print 0.  If the method decides
6910946SSangeeta.Misra@Sun.COM  * that the server is dead, it should print -1 to its STDOUT.
7010946SSangeeta.Misra@Sun.COM  *
7110946SSangeeta.Misra@Sun.COM  * By default, an user-supplied health check probe process will
7210946SSangeeta.Misra@Sun.COM  * also run with the same set of privileges as ILB's built-in
7310946SSangeeta.Misra@Sun.COM  * probes.  If the administrator has an user-supplied health check
7410946SSangeeta.Misra@Sun.COM  * program that requires a larger privilege set, he/she will have
7510946SSangeeta.Misra@Sun.COM  * to implement setuid program.
7610946SSangeeta.Misra@Sun.COM  *
7710946SSangeeta.Misra@Sun.COM  * Each health check will have a timeout, such that if the health
7810946SSangeeta.Misra@Sun.COM  * check process is hung, it will be killed after the timeout interval
7910946SSangeeta.Misra@Sun.COM  * and the daemon will notify the kernel ILB engine of the server's
8010946SSangeeta.Misra@Sun.COM  * unresponsiveness, so that load distribution can be appropriately
8110946SSangeeta.Misra@Sun.COM  * adjusted.  If on the other hand the health check is successful
8210946SSangeeta.Misra@Sun.COM  * the timeout timer is cancelled.
8310946SSangeeta.Misra@Sun.COM  */
8410946SSangeeta.Misra@Sun.COM 
8510946SSangeeta.Misra@Sun.COM #include <stdio.h>
8610946SSangeeta.Misra@Sun.COM #include <stdlib.h>
8710946SSangeeta.Misra@Sun.COM #include <strings.h>
8810946SSangeeta.Misra@Sun.COM #include <libgen.h>
8910946SSangeeta.Misra@Sun.COM #include <fcntl.h>
9010946SSangeeta.Misra@Sun.COM #include <stddef.h>
9110946SSangeeta.Misra@Sun.COM #include <signal.h>
9210946SSangeeta.Misra@Sun.COM #include <port.h>
9310946SSangeeta.Misra@Sun.COM #include <ctype.h>
9410946SSangeeta.Misra@Sun.COM #include <sys/types.h>
9510946SSangeeta.Misra@Sun.COM #include <sys/wait.h>
9610946SSangeeta.Misra@Sun.COM #include <sys/stat.h>
9710946SSangeeta.Misra@Sun.COM #include <sys/note.h>
9810946SSangeeta.Misra@Sun.COM #include <sys/resource.h>
9910946SSangeeta.Misra@Sun.COM #include <unistd.h>
10010946SSangeeta.Misra@Sun.COM #include <sys/socket.h>
10110946SSangeeta.Misra@Sun.COM #include <errno.h>
10210946SSangeeta.Misra@Sun.COM #include <ucred.h>
10310946SSangeeta.Misra@Sun.COM #include <priv_utils.h>
10410946SSangeeta.Misra@Sun.COM #include <net/if.h>
10510946SSangeeta.Misra@Sun.COM #include <libilb.h>
10610946SSangeeta.Misra@Sun.COM #include <assert.h>
10710946SSangeeta.Misra@Sun.COM #include <inet/ilb.h>
10810946SSangeeta.Misra@Sun.COM #include <libintl.h>
10910946SSangeeta.Misra@Sun.COM #include <fcntl.h>
11010946SSangeeta.Misra@Sun.COM #include <rpcsvc/daemon_utils.h>
11110946SSangeeta.Misra@Sun.COM #include "libilb_impl.h"
11210946SSangeeta.Misra@Sun.COM #include "ilbd.h"
11310946SSangeeta.Misra@Sun.COM 
11410946SSangeeta.Misra@Sun.COM /*
11510946SSangeeta.Misra@Sun.COM  * NOTE: The following needs to be kept up to date.
11610946SSangeeta.Misra@Sun.COM  */
11710946SSangeeta.Misra@Sun.COM #define	ILBD_VERSION	"1.0"
11810946SSangeeta.Misra@Sun.COM #define	ILBD_COPYRIGHT	\
119*12424SSangeeta.Misra@Sun.COM 	"Copyright (c) 2005, 2010, Oracle and/or its affiliates. " \
120*12424SSangeeta.Misra@Sun.COM 	"All rights reserved.\n"
12110946SSangeeta.Misra@Sun.COM 
12210946SSangeeta.Misra@Sun.COM /*
12310946SSangeeta.Misra@Sun.COM  * Global reply buffer to client request.  Note that ilbd is single threaded,
12410946SSangeeta.Misra@Sun.COM  * so a global buffer is OK.  If ilbd becomes multi-threaded, this needs to
12510946SSangeeta.Misra@Sun.COM  * be changed.
12610946SSangeeta.Misra@Sun.COM  */
12710946SSangeeta.Misra@Sun.COM static uint32_t reply_buf[ILBD_MSG_SIZE / sizeof (uint32_t)];
12810946SSangeeta.Misra@Sun.COM 
12910946SSangeeta.Misra@Sun.COM static void
ilbd_free_cli(ilbd_client_t * cli)13010946SSangeeta.Misra@Sun.COM ilbd_free_cli(ilbd_client_t *cli)
13110946SSangeeta.Misra@Sun.COM {
13210946SSangeeta.Misra@Sun.COM 	(void) close(cli->cli_sd);
13310946SSangeeta.Misra@Sun.COM 	if (cli->cli_cmd == ILBD_SHOW_NAT)
13410946SSangeeta.Misra@Sun.COM 		ilbd_show_nat_cleanup();
13510946SSangeeta.Misra@Sun.COM 	if (cli->cli_cmd == ILBD_SHOW_PERSIST)
13610946SSangeeta.Misra@Sun.COM 		ilbd_show_sticky_cleanup();
13710946SSangeeta.Misra@Sun.COM 	if (cli->cli_saved_reply != NULL)
13810946SSangeeta.Misra@Sun.COM 		free(cli->cli_saved_reply);
13910946SSangeeta.Misra@Sun.COM 	free(cli->cli_pw_buf);
14010946SSangeeta.Misra@Sun.COM 	free(cli);
14110946SSangeeta.Misra@Sun.COM }
14210946SSangeeta.Misra@Sun.COM 
14310946SSangeeta.Misra@Sun.COM static void
ilbd_reset_kernel_state(void)14410946SSangeeta.Misra@Sun.COM ilbd_reset_kernel_state(void)
14510946SSangeeta.Misra@Sun.COM {
14610946SSangeeta.Misra@Sun.COM 	ilb_status_t	rc;
14710946SSangeeta.Misra@Sun.COM 	ilb_name_cmd_t	kcmd;
14810946SSangeeta.Misra@Sun.COM 
14910946SSangeeta.Misra@Sun.COM 	kcmd.cmd = ILB_DESTROY_RULE;
15010946SSangeeta.Misra@Sun.COM 	kcmd.flags = ILB_RULE_ALLRULES;
15110946SSangeeta.Misra@Sun.COM 	kcmd.name[0] = '\0';
15210946SSangeeta.Misra@Sun.COM 
15310946SSangeeta.Misra@Sun.COM 	rc = do_ioctl(&kcmd, 0);
15410946SSangeeta.Misra@Sun.COM 	if (rc != ILB_STATUS_OK)
15510946SSangeeta.Misra@Sun.COM 		logdebug("ilbd_reset_kernel_state: do_ioctl failed: %s",
15610946SSangeeta.Misra@Sun.COM 		    strerror(errno));
15710946SSangeeta.Misra@Sun.COM }
15810946SSangeeta.Misra@Sun.COM 
15910946SSangeeta.Misra@Sun.COM /* Signal handler to do clean up. */
16010946SSangeeta.Misra@Sun.COM /* ARGSUSED */
16110946SSangeeta.Misra@Sun.COM static void
ilbd_cleanup(int sig)16210946SSangeeta.Misra@Sun.COM ilbd_cleanup(int sig)
16310946SSangeeta.Misra@Sun.COM {
16410946SSangeeta.Misra@Sun.COM 	(void) remove(SOCKET_PATH);
16510946SSangeeta.Misra@Sun.COM 	ilbd_reset_kernel_state();
16610946SSangeeta.Misra@Sun.COM 	exit(0);
16710946SSangeeta.Misra@Sun.COM }
16810946SSangeeta.Misra@Sun.COM 
16910946SSangeeta.Misra@Sun.COM /*
17010946SSangeeta.Misra@Sun.COM  * Create a socket and return it to caller.  If there is a failure, this
17110946SSangeeta.Misra@Sun.COM  * function calls exit(2).  Hence it always returns a valid listener socket.
17210946SSangeeta.Misra@Sun.COM  *
17310946SSangeeta.Misra@Sun.COM  * Note that this function is called before ilbd becomes a daemon.  So
17410946SSangeeta.Misra@Sun.COM  * we call perror(3C) to print out error message directly so that SMF can
17510946SSangeeta.Misra@Sun.COM  * catch them.
17610946SSangeeta.Misra@Sun.COM  */
17710946SSangeeta.Misra@Sun.COM static int
ilbd_create_client_socket(void)17810946SSangeeta.Misra@Sun.COM ilbd_create_client_socket(void)
17910946SSangeeta.Misra@Sun.COM {
18010946SSangeeta.Misra@Sun.COM 	int			s;
18110946SSangeeta.Misra@Sun.COM 	mode_t			omask;
18210946SSangeeta.Misra@Sun.COM 	struct sockaddr_un	sa;
18310946SSangeeta.Misra@Sun.COM 	int			sobufsz;
18410946SSangeeta.Misra@Sun.COM 
18510946SSangeeta.Misra@Sun.COM 	s = socket(PF_UNIX, SOCK_SEQPACKET, 0);
18610946SSangeeta.Misra@Sun.COM 	if (s == -1) {
18710946SSangeeta.Misra@Sun.COM 		perror("ilbd_create_client_socket: socket to"
18810946SSangeeta.Misra@Sun.COM 		    " client failed");
18910946SSangeeta.Misra@Sun.COM 		exit(errno);
19010946SSangeeta.Misra@Sun.COM 	}
19110946SSangeeta.Misra@Sun.COM 	if (fcntl(s, F_SETFD, FD_CLOEXEC) == -1) {
19210946SSangeeta.Misra@Sun.COM 		perror("ilbd_create_client_socket: fcntl(FD_CLOEXEC)");
19310946SSangeeta.Misra@Sun.COM 		exit(errno);
19410946SSangeeta.Misra@Sun.COM 	}
19510946SSangeeta.Misra@Sun.COM 
19610946SSangeeta.Misra@Sun.COM 	sobufsz = ILBD_MSG_SIZE;
19710946SSangeeta.Misra@Sun.COM 	if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &sobufsz,
19810946SSangeeta.Misra@Sun.COM 	    sizeof (sobufsz)) != 0) {
19910946SSangeeta.Misra@Sun.COM 		perror("ilbd_creat_client_socket: setsockopt(SO_SNDBUF) "
20010946SSangeeta.Misra@Sun.COM 		    "failed");
20110946SSangeeta.Misra@Sun.COM 		exit(errno);
20210946SSangeeta.Misra@Sun.COM 	}
20310946SSangeeta.Misra@Sun.COM 	if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &sobufsz,
20410946SSangeeta.Misra@Sun.COM 	    sizeof (sobufsz)) != 0) {
20510946SSangeeta.Misra@Sun.COM 		perror("ilbd_creat_client_socket: setsockopt(SO_RCVBUF) "
20610946SSangeeta.Misra@Sun.COM 		    "failed");
20710946SSangeeta.Misra@Sun.COM 		exit(errno);
20810946SSangeeta.Misra@Sun.COM 	}
20910946SSangeeta.Misra@Sun.COM 
21010946SSangeeta.Misra@Sun.COM 	/*
21110946SSangeeta.Misra@Sun.COM 	 * since everybody can talk to us, we need to open up permissions
21210946SSangeeta.Misra@Sun.COM 	 * we check peer privileges on a per-operation basis.
21310946SSangeeta.Misra@Sun.COM 	 * This is no security issue as long as we're single-threaded.
21410946SSangeeta.Misra@Sun.COM 	 */
21510946SSangeeta.Misra@Sun.COM 	omask = umask(0);
21610946SSangeeta.Misra@Sun.COM 
21710946SSangeeta.Misra@Sun.COM 	/* just in case we didn't clean up properly after last exit */
21810946SSangeeta.Misra@Sun.COM 	(void) remove(SOCKET_PATH);
21910946SSangeeta.Misra@Sun.COM 
22010946SSangeeta.Misra@Sun.COM 	bzero(&sa, sizeof (sa));
22110946SSangeeta.Misra@Sun.COM 	sa.sun_family = AF_UNIX;
22210946SSangeeta.Misra@Sun.COM 	(void) strlcpy(sa.sun_path, SOCKET_PATH, sizeof (sa.sun_path));
22310946SSangeeta.Misra@Sun.COM 
22410946SSangeeta.Misra@Sun.COM 	if (bind(s, (struct sockaddr *)&sa, sizeof (sa)) != 0) {
22510946SSangeeta.Misra@Sun.COM 		perror("ilbd_create_client_socket(): bind to client"
22610946SSangeeta.Misra@Sun.COM 		    " socket failed");
22710946SSangeeta.Misra@Sun.COM 		exit(errno);
22810946SSangeeta.Misra@Sun.COM 	}
22910946SSangeeta.Misra@Sun.COM 
23010946SSangeeta.Misra@Sun.COM 	/* re-instate old umask */
23110946SSangeeta.Misra@Sun.COM 	(void) umask(omask);
23210946SSangeeta.Misra@Sun.COM 
23310946SSangeeta.Misra@Sun.COM #define	QLEN	16
23410946SSangeeta.Misra@Sun.COM 
23510946SSangeeta.Misra@Sun.COM 	if (listen(s, QLEN) != 0) {
23610946SSangeeta.Misra@Sun.COM 		perror("ilbd_create_client_socket: listen to client"
23710946SSangeeta.Misra@Sun.COM 		    " socket failed");
23810946SSangeeta.Misra@Sun.COM 		exit(errno);
23910946SSangeeta.Misra@Sun.COM 	}
24010946SSangeeta.Misra@Sun.COM 
24110946SSangeeta.Misra@Sun.COM 	(void) signal(SIGHUP, SIG_IGN);
24210946SSangeeta.Misra@Sun.COM 	(void) signal(SIGPIPE, SIG_IGN);
24310946SSangeeta.Misra@Sun.COM 	(void) signal(SIGSTOP, SIG_IGN);
24410946SSangeeta.Misra@Sun.COM 	(void) signal(SIGTSTP, SIG_IGN);
24510946SSangeeta.Misra@Sun.COM 	(void) signal(SIGTTIN, SIG_IGN);
24610946SSangeeta.Misra@Sun.COM 	(void) signal(SIGTTOU, SIG_IGN);
24710946SSangeeta.Misra@Sun.COM 
24810946SSangeeta.Misra@Sun.COM 	(void) signal(SIGINT, ilbd_cleanup);
24910946SSangeeta.Misra@Sun.COM 	(void) signal(SIGTERM, ilbd_cleanup);
25010946SSangeeta.Misra@Sun.COM 	(void) signal(SIGQUIT, ilbd_cleanup);
25110946SSangeeta.Misra@Sun.COM 
25210946SSangeeta.Misra@Sun.COM 	return (s);
25310946SSangeeta.Misra@Sun.COM }
25410946SSangeeta.Misra@Sun.COM 
25510946SSangeeta.Misra@Sun.COM /*
25610946SSangeeta.Misra@Sun.COM  * Return the minimum size of a given request.  The returned size does not
25710946SSangeeta.Misra@Sun.COM  * include the variable part of a request.
25810946SSangeeta.Misra@Sun.COM  */
25910946SSangeeta.Misra@Sun.COM static size_t
ilbd_cmd_size(const ilb_comm_t * ic)26010946SSangeeta.Misra@Sun.COM ilbd_cmd_size(const ilb_comm_t *ic)
26110946SSangeeta.Misra@Sun.COM {
26210946SSangeeta.Misra@Sun.COM 	size_t cmd_sz;
26310946SSangeeta.Misra@Sun.COM 
26410946SSangeeta.Misra@Sun.COM 	cmd_sz = sizeof (*ic);
26510946SSangeeta.Misra@Sun.COM 	switch (ic->ic_cmd) {
26610946SSangeeta.Misra@Sun.COM 	case ILBD_RETRIEVE_SG_NAMES:
26710946SSangeeta.Misra@Sun.COM 	case ILBD_RETRIEVE_RULE_NAMES:
26810946SSangeeta.Misra@Sun.COM 	case ILBD_RETRIEVE_HC_NAMES:
26910946SSangeeta.Misra@Sun.COM 	case ILBD_CMD_OK:
27010946SSangeeta.Misra@Sun.COM 		break;
27110946SSangeeta.Misra@Sun.COM 	case ILBD_CMD_ERROR:
27210946SSangeeta.Misra@Sun.COM 		cmd_sz += sizeof (ilb_status_t);
27310946SSangeeta.Misra@Sun.COM 		break;
27410946SSangeeta.Misra@Sun.COM 	case ILBD_RETRIEVE_SG_HOSTS:
27510946SSangeeta.Misra@Sun.COM 	case ILBD_CREATE_SERVERGROUP:
27610946SSangeeta.Misra@Sun.COM 	case ILBD_DESTROY_SERVERGROUP:
27710946SSangeeta.Misra@Sun.COM 	case ILBD_DESTROY_RULE:
27810946SSangeeta.Misra@Sun.COM 	case ILBD_ENABLE_RULE:
27910946SSangeeta.Misra@Sun.COM 	case ILBD_DISABLE_RULE:
28010946SSangeeta.Misra@Sun.COM 	case ILBD_RETRIEVE_RULE:
28110946SSangeeta.Misra@Sun.COM 	case ILBD_DESTROY_HC:
28210946SSangeeta.Misra@Sun.COM 	case ILBD_GET_HC_INFO:
28310946SSangeeta.Misra@Sun.COM 	case ILBD_GET_HC_SRVS:
28410946SSangeeta.Misra@Sun.COM 		cmd_sz += sizeof (ilbd_name_t);
28510946SSangeeta.Misra@Sun.COM 		break;
28610946SSangeeta.Misra@Sun.COM 	case ILBD_ENABLE_SERVER:
28710946SSangeeta.Misra@Sun.COM 	case ILBD_DISABLE_SERVER:
28810946SSangeeta.Misra@Sun.COM 	case ILBD_ADD_SERVER_TO_GROUP:
28910946SSangeeta.Misra@Sun.COM 	case ILBD_REM_SERVER_FROM_GROUP:
29010946SSangeeta.Misra@Sun.COM 		cmd_sz += sizeof (ilb_sg_info_t);
29110946SSangeeta.Misra@Sun.COM 		break;
29210946SSangeeta.Misra@Sun.COM 	case ILBD_SRV_ADDR2ID:
29310946SSangeeta.Misra@Sun.COM 	case ILBD_SRV_ID2ADDR:
29410946SSangeeta.Misra@Sun.COM 		cmd_sz += sizeof (ilb_sg_info_t) + sizeof (ilb_sg_srv_t);
29510946SSangeeta.Misra@Sun.COM 		break;
29610946SSangeeta.Misra@Sun.COM 	case ILBD_CREATE_RULE:
29710946SSangeeta.Misra@Sun.COM 		cmd_sz += sizeof (ilb_rule_info_t);
29810946SSangeeta.Misra@Sun.COM 		break;
29910946SSangeeta.Misra@Sun.COM 	case ILBD_CREATE_HC:
30010946SSangeeta.Misra@Sun.COM 		cmd_sz += sizeof (ilb_hc_info_t);
30110946SSangeeta.Misra@Sun.COM 		break;
30210946SSangeeta.Misra@Sun.COM 	case ILBD_SHOW_NAT:
30310946SSangeeta.Misra@Sun.COM 	case ILBD_SHOW_PERSIST:
30410946SSangeeta.Misra@Sun.COM 		cmd_sz += sizeof (ilb_show_info_t);
30510946SSangeeta.Misra@Sun.COM 		break;
30610946SSangeeta.Misra@Sun.COM 	}
30710946SSangeeta.Misra@Sun.COM 
30810946SSangeeta.Misra@Sun.COM 	return (cmd_sz);
30910946SSangeeta.Misra@Sun.COM }
31010946SSangeeta.Misra@Sun.COM 
31110946SSangeeta.Misra@Sun.COM /*
31210946SSangeeta.Misra@Sun.COM  * Given a request and its size, check that the size is big enough to
31310946SSangeeta.Misra@Sun.COM  * contain the variable part of a request.
31410946SSangeeta.Misra@Sun.COM  */
31510946SSangeeta.Misra@Sun.COM static ilb_status_t
ilbd_check_req_size(ilb_comm_t * ic,size_t ic_sz)31610946SSangeeta.Misra@Sun.COM ilbd_check_req_size(ilb_comm_t *ic, size_t ic_sz)
31710946SSangeeta.Misra@Sun.COM {
31810946SSangeeta.Misra@Sun.COM 	ilb_status_t rc = ILB_STATUS_OK;
31910946SSangeeta.Misra@Sun.COM 	ilb_sg_info_t *sg_info;
32010946SSangeeta.Misra@Sun.COM 	ilbd_namelist_t *nlist;
32110946SSangeeta.Misra@Sun.COM 
32210946SSangeeta.Misra@Sun.COM 	switch (ic->ic_cmd) {
32310946SSangeeta.Misra@Sun.COM 	case ILBD_CREATE_SERVERGROUP:
32410946SSangeeta.Misra@Sun.COM 	case ILBD_ENABLE_SERVER:
32510946SSangeeta.Misra@Sun.COM 	case ILBD_DISABLE_SERVER:
32610946SSangeeta.Misra@Sun.COM 	case ILBD_ADD_SERVER_TO_GROUP:
32710946SSangeeta.Misra@Sun.COM 	case ILBD_REM_SERVER_FROM_GROUP:
32810946SSangeeta.Misra@Sun.COM 		sg_info = (ilb_sg_info_t *)&ic->ic_data;
32910946SSangeeta.Misra@Sun.COM 
33010946SSangeeta.Misra@Sun.COM 		if (ic_sz < ilbd_cmd_size(ic) + sg_info->sg_srvcount *
33110946SSangeeta.Misra@Sun.COM 		    sizeof (ilb_sg_srv_t)) {
33210946SSangeeta.Misra@Sun.COM 			rc = ILB_STATUS_EINVAL;
33310946SSangeeta.Misra@Sun.COM 		}
33410946SSangeeta.Misra@Sun.COM 		break;
33510946SSangeeta.Misra@Sun.COM 	case ILBD_ENABLE_RULE:
33610946SSangeeta.Misra@Sun.COM 	case ILBD_DISABLE_RULE:
33710946SSangeeta.Misra@Sun.COM 	case ILBD_DESTROY_RULE:
33810946SSangeeta.Misra@Sun.COM 		nlist = (ilbd_namelist_t *)&ic->ic_data;
33910946SSangeeta.Misra@Sun.COM 
34010946SSangeeta.Misra@Sun.COM 		if (ic_sz < ilbd_cmd_size(ic) + nlist->ilbl_count *
34110946SSangeeta.Misra@Sun.COM 		    sizeof (ilbd_name_t)) {
34210946SSangeeta.Misra@Sun.COM 			rc = ILB_STATUS_EINVAL;
34310946SSangeeta.Misra@Sun.COM 		}
34410946SSangeeta.Misra@Sun.COM 		break;
34510946SSangeeta.Misra@Sun.COM 	}
34610946SSangeeta.Misra@Sun.COM 	return (rc);
34710946SSangeeta.Misra@Sun.COM }
34810946SSangeeta.Misra@Sun.COM 
34910946SSangeeta.Misra@Sun.COM /*
35010946SSangeeta.Misra@Sun.COM  * this function *relies* on a complete message/data struct
35110946SSangeeta.Misra@Sun.COM  * being passed in (currently via the SOCK_SEQPACKET socket type).
35210946SSangeeta.Misra@Sun.COM  *
35310946SSangeeta.Misra@Sun.COM  * Note that the size of ip is at most ILBD_MSG_SIZE.
35410946SSangeeta.Misra@Sun.COM  */
35510946SSangeeta.Misra@Sun.COM static ilb_status_t
consume_common_struct(ilb_comm_t * ic,size_t ic_sz,ilbd_client_t * cli,int ev_port)35610946SSangeeta.Misra@Sun.COM consume_common_struct(ilb_comm_t *ic, size_t ic_sz, ilbd_client_t *cli,
35710946SSangeeta.Misra@Sun.COM     int ev_port)
35810946SSangeeta.Misra@Sun.COM {
35910946SSangeeta.Misra@Sun.COM 	ilb_status_t	rc;
36010946SSangeeta.Misra@Sun.COM 	struct passwd	*ps;
36110946SSangeeta.Misra@Sun.COM 	size_t		rbufsz;
36210946SSangeeta.Misra@Sun.COM 	ssize_t		ret;
36310946SSangeeta.Misra@Sun.COM 	boolean_t	standard_reply = B_TRUE;
36410946SSangeeta.Misra@Sun.COM 	ilbd_name_t	name;
36510946SSangeeta.Misra@Sun.COM 
36610946SSangeeta.Misra@Sun.COM 	/*
36710946SSangeeta.Misra@Sun.COM 	 * cli_ev must be overridden during handling of individual commands,
36810946SSangeeta.Misra@Sun.COM 	 * if there's a special need; otherwise, leave this for
36910946SSangeeta.Misra@Sun.COM 	 * the "default" case
37010946SSangeeta.Misra@Sun.COM 	 */
37110946SSangeeta.Misra@Sun.COM 	cli->cli_ev = ILBD_EVENT_REQ;
37210946SSangeeta.Misra@Sun.COM 
37310946SSangeeta.Misra@Sun.COM 	ps = &cli->cli_pw;
37410946SSangeeta.Misra@Sun.COM 	rbufsz = ILBD_MSG_SIZE;
37510946SSangeeta.Misra@Sun.COM 
37610946SSangeeta.Misra@Sun.COM 	/* Sanity check on the size of the static part of a request. */
37710946SSangeeta.Misra@Sun.COM 	if (ic_sz < ilbd_cmd_size(ic)) {
37810946SSangeeta.Misra@Sun.COM 		rc = ILB_STATUS_EINVAL;
37910946SSangeeta.Misra@Sun.COM 		goto out;
38010946SSangeeta.Misra@Sun.COM 	}
38110946SSangeeta.Misra@Sun.COM 
38210946SSangeeta.Misra@Sun.COM 	switch (ic->ic_cmd) {
38310946SSangeeta.Misra@Sun.COM 	case ILBD_CREATE_SERVERGROUP: {
38410946SSangeeta.Misra@Sun.COM 		ilb_sg_info_t sg_info;
38510946SSangeeta.Misra@Sun.COM 
38610946SSangeeta.Misra@Sun.COM 		/*
38710946SSangeeta.Misra@Sun.COM 		 * ilbd_create_sg() only needs the sg_name field.  But it
38810946SSangeeta.Misra@Sun.COM 		 * takes in a ilb_sg_info_t because it is used as a callback
38910946SSangeeta.Misra@Sun.COM 		 * in ilbd_walk_sg_pgs().
39010946SSangeeta.Misra@Sun.COM 		 */
39110946SSangeeta.Misra@Sun.COM 		(void) strlcpy(sg_info.sg_name, (char *)&(ic->ic_data),
39210946SSangeeta.Misra@Sun.COM 		    sizeof (sg_info.sg_name));
39310946SSangeeta.Misra@Sun.COM 		rc = ilbd_create_sg(&sg_info, ev_port, ps,
39410946SSangeeta.Misra@Sun.COM 		    cli->cli_peer_ucredp);
39510946SSangeeta.Misra@Sun.COM 		break;
39610946SSangeeta.Misra@Sun.COM 	}
39710946SSangeeta.Misra@Sun.COM 
39810946SSangeeta.Misra@Sun.COM 	case ILBD_DESTROY_SERVERGROUP:
39910946SSangeeta.Misra@Sun.COM 		(void) strlcpy(name, (char *)&(ic->ic_data), sizeof (name));
40010946SSangeeta.Misra@Sun.COM 		rc = ilbd_destroy_sg(name, ps, cli->cli_peer_ucredp);
40110946SSangeeta.Misra@Sun.COM 		break;
40210946SSangeeta.Misra@Sun.COM 
40310946SSangeeta.Misra@Sun.COM 	case ILBD_ADD_SERVER_TO_GROUP:
40410946SSangeeta.Misra@Sun.COM 		if ((rc = ilbd_check_req_size(ic, ic_sz)) != ILB_STATUS_OK)
40510946SSangeeta.Misra@Sun.COM 			break;
40610946SSangeeta.Misra@Sun.COM 		rc = ilbd_add_server_to_group((ilb_sg_info_t *)&ic->ic_data,
40710946SSangeeta.Misra@Sun.COM 		    ev_port, ps, cli->cli_peer_ucredp);
40810946SSangeeta.Misra@Sun.COM 		break;
40910946SSangeeta.Misra@Sun.COM 
41010946SSangeeta.Misra@Sun.COM 	case ILBD_REM_SERVER_FROM_GROUP:
41110946SSangeeta.Misra@Sun.COM 		if ((rc = ilbd_check_req_size(ic, ic_sz)) != ILB_STATUS_OK)
41210946SSangeeta.Misra@Sun.COM 			break;
41310946SSangeeta.Misra@Sun.COM 		rc = ilbd_rem_server_from_group((ilb_sg_info_t *)&ic->ic_data,
41410946SSangeeta.Misra@Sun.COM 		    ev_port, ps, cli->cli_peer_ucredp);
41510946SSangeeta.Misra@Sun.COM 		break;
41610946SSangeeta.Misra@Sun.COM 
41710946SSangeeta.Misra@Sun.COM 	case ILBD_ENABLE_SERVER:
41810946SSangeeta.Misra@Sun.COM 		if ((rc = ilbd_check_req_size(ic, ic_sz)) != ILB_STATUS_OK)
41910946SSangeeta.Misra@Sun.COM 			break;
42010946SSangeeta.Misra@Sun.COM 		rc = ilbd_enable_server((ilb_sg_info_t *)&ic->ic_data, ps,
42110946SSangeeta.Misra@Sun.COM 		    cli->cli_peer_ucredp);
42210946SSangeeta.Misra@Sun.COM 		break;
42310946SSangeeta.Misra@Sun.COM 
42410946SSangeeta.Misra@Sun.COM 	case ILBD_DISABLE_SERVER:
42510946SSangeeta.Misra@Sun.COM 		if ((rc = ilbd_check_req_size(ic, ic_sz)) != ILB_STATUS_OK)
42610946SSangeeta.Misra@Sun.COM 			break;
42710946SSangeeta.Misra@Sun.COM 		rc = ilbd_disable_server((ilb_sg_info_t *)&ic->ic_data, ps,
42810946SSangeeta.Misra@Sun.COM 		    cli->cli_peer_ucredp);
42910946SSangeeta.Misra@Sun.COM 		break;
43010946SSangeeta.Misra@Sun.COM 
43110946SSangeeta.Misra@Sun.COM 	case ILBD_SRV_ADDR2ID:
43210946SSangeeta.Misra@Sun.COM 		rc = ilbd_address_to_srvID((ilb_sg_info_t *)&ic->ic_data,
43310946SSangeeta.Misra@Sun.COM 		    reply_buf, &rbufsz);
43410946SSangeeta.Misra@Sun.COM 		if (rc == ILB_STATUS_OK)
43510946SSangeeta.Misra@Sun.COM 			standard_reply = B_FALSE;
43610946SSangeeta.Misra@Sun.COM 		break;
43710946SSangeeta.Misra@Sun.COM 
43810946SSangeeta.Misra@Sun.COM 	case ILBD_SRV_ID2ADDR:
43910946SSangeeta.Misra@Sun.COM 		rc = ilbd_srvID_to_address((ilb_sg_info_t *)&ic->ic_data,
44010946SSangeeta.Misra@Sun.COM 		    reply_buf, &rbufsz);
44110946SSangeeta.Misra@Sun.COM 		if (rc == ILB_STATUS_OK)
44210946SSangeeta.Misra@Sun.COM 			standard_reply = B_FALSE;
44310946SSangeeta.Misra@Sun.COM 		break;
44410946SSangeeta.Misra@Sun.COM 
44510946SSangeeta.Misra@Sun.COM 	case ILBD_RETRIEVE_SG_HOSTS:
44610946SSangeeta.Misra@Sun.COM 		(void) strlcpy(name, (char *)&(ic->ic_data), sizeof (name));
44710946SSangeeta.Misra@Sun.COM 		rc = ilbd_retrieve_sg_hosts(name, reply_buf, &rbufsz);
44810946SSangeeta.Misra@Sun.COM 		if (rc == ILB_STATUS_OK)
44910946SSangeeta.Misra@Sun.COM 			standard_reply = B_FALSE;
45010946SSangeeta.Misra@Sun.COM 		break;
45110946SSangeeta.Misra@Sun.COM 
45210946SSangeeta.Misra@Sun.COM 	case ILBD_RETRIEVE_SG_NAMES:
45310946SSangeeta.Misra@Sun.COM 	case ILBD_RETRIEVE_RULE_NAMES:
45410946SSangeeta.Misra@Sun.COM 	case ILBD_RETRIEVE_HC_NAMES:
45510946SSangeeta.Misra@Sun.COM 		rc = ilbd_retrieve_names(ic->ic_cmd, reply_buf, &rbufsz);
45610946SSangeeta.Misra@Sun.COM 		if (rc == ILB_STATUS_OK)
45710946SSangeeta.Misra@Sun.COM 			standard_reply = B_FALSE;
45810946SSangeeta.Misra@Sun.COM 		break;
45910946SSangeeta.Misra@Sun.COM 
46010946SSangeeta.Misra@Sun.COM 	case ILBD_CREATE_RULE:
46110946SSangeeta.Misra@Sun.COM 		rc = ilbd_create_rule((ilb_rule_info_t *)&ic->ic_data, ev_port,
46210946SSangeeta.Misra@Sun.COM 		    ps, cli->cli_peer_ucredp);
46310946SSangeeta.Misra@Sun.COM 		break;
46410946SSangeeta.Misra@Sun.COM 
46510946SSangeeta.Misra@Sun.COM 	case ILBD_DESTROY_RULE:
46610946SSangeeta.Misra@Sun.COM 		/* Copy the name to ensure that name is NULL terminated. */
46710946SSangeeta.Misra@Sun.COM 		(void) strlcpy(name, (char *)&(ic->ic_data), sizeof (name));
46810946SSangeeta.Misra@Sun.COM 		rc = ilbd_destroy_rule(name, ps, cli->cli_peer_ucredp);
46910946SSangeeta.Misra@Sun.COM 		break;
47010946SSangeeta.Misra@Sun.COM 
47110946SSangeeta.Misra@Sun.COM 	case ILBD_ENABLE_RULE:
47210946SSangeeta.Misra@Sun.COM 		(void) strlcpy(name, (char *)&(ic->ic_data), sizeof (name));
47310946SSangeeta.Misra@Sun.COM 		rc = ilbd_enable_rule(name, ps, cli->cli_peer_ucredp);
47410946SSangeeta.Misra@Sun.COM 		break;
47510946SSangeeta.Misra@Sun.COM 
47610946SSangeeta.Misra@Sun.COM 	case ILBD_DISABLE_RULE:
47710946SSangeeta.Misra@Sun.COM 		(void) strlcpy(name, (char *)&(ic->ic_data), sizeof (name));
47810946SSangeeta.Misra@Sun.COM 		rc = ilbd_disable_rule(name, ps, cli->cli_peer_ucredp);
47910946SSangeeta.Misra@Sun.COM 		break;
48010946SSangeeta.Misra@Sun.COM 
48110946SSangeeta.Misra@Sun.COM 	case ILBD_RETRIEVE_RULE:
48210946SSangeeta.Misra@Sun.COM 		(void) strlcpy(name, (char *)&(ic->ic_data), sizeof (name));
48310946SSangeeta.Misra@Sun.COM 		rc = ilbd_retrieve_rule(name, reply_buf, &rbufsz);
48410946SSangeeta.Misra@Sun.COM 		if (rc == ILB_STATUS_OK)
48510946SSangeeta.Misra@Sun.COM 			standard_reply = B_FALSE;
48610946SSangeeta.Misra@Sun.COM 		break;
48710946SSangeeta.Misra@Sun.COM 
48810946SSangeeta.Misra@Sun.COM 	case ILBD_CREATE_HC:
48910946SSangeeta.Misra@Sun.COM 		rc = ilbd_create_hc((ilb_hc_info_t *)&ic->ic_data, ev_port, ps,
49010946SSangeeta.Misra@Sun.COM 		    cli->cli_peer_ucredp);
49110946SSangeeta.Misra@Sun.COM 		break;
49210946SSangeeta.Misra@Sun.COM 
49310946SSangeeta.Misra@Sun.COM 	case ILBD_DESTROY_HC:
49410946SSangeeta.Misra@Sun.COM 		(void) strlcpy(name, (char *)&(ic->ic_data), sizeof (name));
49510946SSangeeta.Misra@Sun.COM 		rc = ilbd_destroy_hc(name, ps, cli->cli_peer_ucredp);
49610946SSangeeta.Misra@Sun.COM 		break;
49710946SSangeeta.Misra@Sun.COM 
49810946SSangeeta.Misra@Sun.COM 	case ILBD_GET_HC_INFO:
49910946SSangeeta.Misra@Sun.COM 		(void) strlcpy(name, (char *)&(ic->ic_data), sizeof (name));
50010946SSangeeta.Misra@Sun.COM 		rc = ilbd_get_hc_info(name, reply_buf, &rbufsz);
50110946SSangeeta.Misra@Sun.COM 		if (rc == ILB_STATUS_OK)
50210946SSangeeta.Misra@Sun.COM 			standard_reply = B_FALSE;
50310946SSangeeta.Misra@Sun.COM 		break;
50410946SSangeeta.Misra@Sun.COM 
50510946SSangeeta.Misra@Sun.COM 	case ILBD_GET_HC_SRVS:
50610946SSangeeta.Misra@Sun.COM 		(void) strlcpy(name, (char *)&(ic->ic_data), sizeof (name));
50710946SSangeeta.Misra@Sun.COM 		rc = ilbd_get_hc_srvs(name, reply_buf, &rbufsz);
50810946SSangeeta.Misra@Sun.COM 		if (rc == ILB_STATUS_OK)
50910946SSangeeta.Misra@Sun.COM 			standard_reply = B_FALSE;
51010946SSangeeta.Misra@Sun.COM 		break;
51110946SSangeeta.Misra@Sun.COM 
51210946SSangeeta.Misra@Sun.COM 	case ILBD_SHOW_NAT:
51310946SSangeeta.Misra@Sun.COM 		rc = ilbd_show_nat(cli, ic, reply_buf, &rbufsz);
51410946SSangeeta.Misra@Sun.COM 		if (rc == ILB_STATUS_OK)
51510946SSangeeta.Misra@Sun.COM 			standard_reply = B_FALSE;
51610946SSangeeta.Misra@Sun.COM 		break;
51710946SSangeeta.Misra@Sun.COM 
51810946SSangeeta.Misra@Sun.COM 	case ILBD_SHOW_PERSIST:
51910946SSangeeta.Misra@Sun.COM 		rc = ilbd_show_sticky(cli, ic, reply_buf, &rbufsz);
52010946SSangeeta.Misra@Sun.COM 		if (rc == ILB_STATUS_OK)
52110946SSangeeta.Misra@Sun.COM 			standard_reply = B_FALSE;
52210946SSangeeta.Misra@Sun.COM 		break;
52310946SSangeeta.Misra@Sun.COM 
52410946SSangeeta.Misra@Sun.COM 	default:
52510946SSangeeta.Misra@Sun.COM 		logdebug("consume_common_struct: unknown command");
52610946SSangeeta.Misra@Sun.COM 		rc = ILB_STATUS_INVAL_CMD;
52710946SSangeeta.Misra@Sun.COM 		break;
52810946SSangeeta.Misra@Sun.COM 	}
52910946SSangeeta.Misra@Sun.COM 
53010946SSangeeta.Misra@Sun.COM out:
53110946SSangeeta.Misra@Sun.COM 	/*
53210946SSangeeta.Misra@Sun.COM 	 * The message exchange is always in pairs, request/response.  If
53310946SSangeeta.Misra@Sun.COM 	 * a transaction requires multiple exchanges, the client will send
53410946SSangeeta.Misra@Sun.COM 	 * in multiple requests to get multiple responses.  The show-nat and
53510946SSangeeta.Misra@Sun.COM 	 * show-persist request are examples of this.  The end of transaction
53610946SSangeeta.Misra@Sun.COM 	 * is marked with ic_flags set to ILB_COMM_END.
53710946SSangeeta.Misra@Sun.COM 	 */
53810946SSangeeta.Misra@Sun.COM 
53910946SSangeeta.Misra@Sun.COM 	/* This is the standard reply. */
54010946SSangeeta.Misra@Sun.COM 	if (standard_reply) {
54110946SSangeeta.Misra@Sun.COM 		if (rc == ILB_STATUS_OK)
54210946SSangeeta.Misra@Sun.COM 			ilbd_reply_ok(reply_buf, &rbufsz);
54310946SSangeeta.Misra@Sun.COM 		else
54410946SSangeeta.Misra@Sun.COM 			ilbd_reply_err(reply_buf, &rbufsz, rc);
54510946SSangeeta.Misra@Sun.COM 	}
54610946SSangeeta.Misra@Sun.COM 
54710946SSangeeta.Misra@Sun.COM 	if ((ret = send(cli->cli_sd, reply_buf, rbufsz, 0)) != rbufsz) {
54810946SSangeeta.Misra@Sun.COM 		if (ret == -1) {
54910946SSangeeta.Misra@Sun.COM 			if (errno != EWOULDBLOCK) {
55010946SSangeeta.Misra@Sun.COM 				logdebug("consume_common_struct: send: %s",
55110946SSangeeta.Misra@Sun.COM 				    strerror(errno));
55210946SSangeeta.Misra@Sun.COM 				rc = ILB_STATUS_SEND;
55310946SSangeeta.Misra@Sun.COM 				goto err_out;
55410946SSangeeta.Misra@Sun.COM 			}
55510946SSangeeta.Misra@Sun.COM 			/*
55610946SSangeeta.Misra@Sun.COM 			 * The reply is blocked, save the reply.  handle_req()
55710946SSangeeta.Misra@Sun.COM 			 * will associate the event port for the re-send.
55810946SSangeeta.Misra@Sun.COM 			 */
55910946SSangeeta.Misra@Sun.COM 			assert(cli->cli_saved_reply == NULL);
56010946SSangeeta.Misra@Sun.COM 			if ((cli->cli_saved_reply = malloc(rbufsz)) == NULL) {
56110946SSangeeta.Misra@Sun.COM 				/*
56210946SSangeeta.Misra@Sun.COM 				 * Set the error to ILB_STATUS_SEND so that
56310946SSangeeta.Misra@Sun.COM 				 * handle_req() will free the client.
56410946SSangeeta.Misra@Sun.COM 				 */
56510946SSangeeta.Misra@Sun.COM 				logdebug("consume_common_struct: failure to "
56610946SSangeeta.Misra@Sun.COM 				    "allocate memory to save reply");
56710946SSangeeta.Misra@Sun.COM 				rc = ILB_STATUS_SEND;
56810946SSangeeta.Misra@Sun.COM 				goto err_out;
56910946SSangeeta.Misra@Sun.COM 			}
57010946SSangeeta.Misra@Sun.COM 			bcopy(reply_buf, cli->cli_saved_reply, rbufsz);
57110946SSangeeta.Misra@Sun.COM 			cli->cli_saved_size = rbufsz;
57210946SSangeeta.Misra@Sun.COM 			return (ILB_STATUS_EWOULDBLOCK);
57310946SSangeeta.Misra@Sun.COM 		}
57410946SSangeeta.Misra@Sun.COM 	}
57510946SSangeeta.Misra@Sun.COM err_out:
57610946SSangeeta.Misra@Sun.COM 	return (rc);
57710946SSangeeta.Misra@Sun.COM }
57810946SSangeeta.Misra@Sun.COM 
57910946SSangeeta.Misra@Sun.COM /*
58010946SSangeeta.Misra@Sun.COM  * Accept a new client request.  A struct ilbd_client_t is allocated to
58110946SSangeeta.Misra@Sun.COM  * store the client info.  The accepted socket is port_associate() with
58210946SSangeeta.Misra@Sun.COM  * the given port.  And the allocated ilbd_client_t struct is passed as
58310946SSangeeta.Misra@Sun.COM  * the user pointer.
58410946SSangeeta.Misra@Sun.COM  */
58510946SSangeeta.Misra@Sun.COM static void
new_req(int ev_port,int listener,void * ev_obj)58610946SSangeeta.Misra@Sun.COM new_req(int ev_port, int listener, void *ev_obj)
58710946SSangeeta.Misra@Sun.COM {
58810946SSangeeta.Misra@Sun.COM 	struct sockaddr	sa;
58910946SSangeeta.Misra@Sun.COM 	int		sa_len;
59010946SSangeeta.Misra@Sun.COM 	int		new_sd;
59110946SSangeeta.Misra@Sun.COM 	int		sflags;
59210946SSangeeta.Misra@Sun.COM 	ilbd_client_t	*cli;
59310946SSangeeta.Misra@Sun.COM 	int		res;
59410946SSangeeta.Misra@Sun.COM 	uid_t		uid;
59510946SSangeeta.Misra@Sun.COM 
59610946SSangeeta.Misra@Sun.COM 	sa_len = sizeof (sa);
59710946SSangeeta.Misra@Sun.COM 	if ((new_sd = accept(listener, &sa, &sa_len)) == -1) {
59810946SSangeeta.Misra@Sun.COM 		/* don't log if we're out of file descriptors */
59910946SSangeeta.Misra@Sun.COM 		if (errno != EINTR && errno != EMFILE)
60010946SSangeeta.Misra@Sun.COM 			logperror("new_req: accept failed");
60110946SSangeeta.Misra@Sun.COM 		goto done;
60210946SSangeeta.Misra@Sun.COM 	}
60310946SSangeeta.Misra@Sun.COM 
60410946SSangeeta.Misra@Sun.COM 	/* Set the new socket to be non-blocking. */
60510946SSangeeta.Misra@Sun.COM 	if ((sflags = fcntl(new_sd, F_GETFL, 0)) == -1) {
60610946SSangeeta.Misra@Sun.COM 		logperror("new_req: fcntl(F_GETFL)");
60710946SSangeeta.Misra@Sun.COM 		goto clean_up;
60810946SSangeeta.Misra@Sun.COM 	}
60910946SSangeeta.Misra@Sun.COM 	if (fcntl(new_sd, F_SETFL, sflags | O_NONBLOCK) == -1) {
61010946SSangeeta.Misra@Sun.COM 		logperror("new_req: fcntl(F_SETFL)");
61110946SSangeeta.Misra@Sun.COM 		goto clean_up;
61210946SSangeeta.Misra@Sun.COM 	}
61310946SSangeeta.Misra@Sun.COM 	if (fcntl(new_sd, F_SETFD, FD_CLOEXEC) == -1) {
61410946SSangeeta.Misra@Sun.COM 		logperror("new_req: fcntl(FD_CLOEXEC)");
61510946SSangeeta.Misra@Sun.COM 		goto clean_up;
61610946SSangeeta.Misra@Sun.COM 	}
61710946SSangeeta.Misra@Sun.COM 	if ((cli = calloc(1, sizeof (ilbd_client_t))) == NULL) {
61810946SSangeeta.Misra@Sun.COM 		logerr("new_req: malloc(ilbd_client_t)");
61910946SSangeeta.Misra@Sun.COM 		goto clean_up;
62010946SSangeeta.Misra@Sun.COM 	}
62110946SSangeeta.Misra@Sun.COM 	res = getpeerucred(new_sd, &cli->cli_peer_ucredp);
62210946SSangeeta.Misra@Sun.COM 	if (res == -1) {
62310946SSangeeta.Misra@Sun.COM 		logperror("new_req: getpeerucred failed");
624*12424SSangeeta.Misra@Sun.COM 		free(cli);
62510946SSangeeta.Misra@Sun.COM 		goto clean_up;
62610946SSangeeta.Misra@Sun.COM 	}
62710946SSangeeta.Misra@Sun.COM 	if ((uid = ucred_getruid(cli->cli_peer_ucredp)) == (uid_t)-1) {
62810946SSangeeta.Misra@Sun.COM 		logperror("new_req: ucred_getruid failed");
629*12424SSangeeta.Misra@Sun.COM 		free(cli);
63010946SSangeeta.Misra@Sun.COM 		goto clean_up;
63110946SSangeeta.Misra@Sun.COM 	}
63210946SSangeeta.Misra@Sun.COM 	cli->cli_pw_bufsz = (size_t)sysconf(_SC_GETPW_R_SIZE_MAX);
63310946SSangeeta.Misra@Sun.COM 	if ((cli->cli_pw_buf = malloc(cli->cli_pw_bufsz)) == NULL) {
63410946SSangeeta.Misra@Sun.COM 		free(cli);
63510946SSangeeta.Misra@Sun.COM 		logerr("new_req: malloc(cli_pw_buf)");
63610946SSangeeta.Misra@Sun.COM 		goto clean_up;
63710946SSangeeta.Misra@Sun.COM 	}
63810946SSangeeta.Misra@Sun.COM 	if (getpwuid_r(uid, &cli->cli_pw, cli->cli_pw_buf,
63910946SSangeeta.Misra@Sun.COM 	    cli->cli_pw_bufsz) == NULL) {
64010946SSangeeta.Misra@Sun.COM 		free(cli->cli_pw_buf);
64110946SSangeeta.Misra@Sun.COM 		free(cli);
64210946SSangeeta.Misra@Sun.COM 		logperror("new_req: invalid user");
64310946SSangeeta.Misra@Sun.COM 		goto clean_up;
64410946SSangeeta.Misra@Sun.COM 	}
64510946SSangeeta.Misra@Sun.COM 	cli->cli_ev = ILBD_EVENT_REQ;
64610946SSangeeta.Misra@Sun.COM 	cli->cli_sd = new_sd;
64710946SSangeeta.Misra@Sun.COM 	cli->cli_cmd = ILBD_BAD_CMD;
64810946SSangeeta.Misra@Sun.COM 	cli->cli_saved_reply = NULL;
64910946SSangeeta.Misra@Sun.COM 	cli->cli_saved_size = 0;
65010946SSangeeta.Misra@Sun.COM 	if (port_associate(ev_port, PORT_SOURCE_FD, new_sd, POLLRDNORM,
65110946SSangeeta.Misra@Sun.COM 	    cli) == -1) {
65210946SSangeeta.Misra@Sun.COM 		logperror("new_req: port_associate(cli) failed");
65310946SSangeeta.Misra@Sun.COM 		free(cli->cli_pw_buf);
65410946SSangeeta.Misra@Sun.COM 		free(cli);
65510946SSangeeta.Misra@Sun.COM clean_up:
65610946SSangeeta.Misra@Sun.COM 		(void) close(new_sd);
65710946SSangeeta.Misra@Sun.COM 	}
65810946SSangeeta.Misra@Sun.COM 
65910946SSangeeta.Misra@Sun.COM done:
66010946SSangeeta.Misra@Sun.COM 	/* Re-associate the listener with the event port. */
66110946SSangeeta.Misra@Sun.COM 	if (port_associate(ev_port, PORT_SOURCE_FD, listener, POLLRDNORM,
66210946SSangeeta.Misra@Sun.COM 	    ev_obj) == -1) {
66310946SSangeeta.Misra@Sun.COM 		logperror("new_req: port_associate(listener) failed");
66410946SSangeeta.Misra@Sun.COM 		exit(1);
66510946SSangeeta.Misra@Sun.COM 	}
66610946SSangeeta.Misra@Sun.COM }
66710946SSangeeta.Misra@Sun.COM 
66810946SSangeeta.Misra@Sun.COM static void
handle_req(int ev_port,ilbd_event_t event,ilbd_client_t * cli)66910946SSangeeta.Misra@Sun.COM handle_req(int ev_port, ilbd_event_t event, ilbd_client_t *cli)
67010946SSangeeta.Misra@Sun.COM {
67110946SSangeeta.Misra@Sun.COM 	/* All request should be smaller than ILBD_MSG_SIZE */
67210946SSangeeta.Misra@Sun.COM 	union {
67310946SSangeeta.Misra@Sun.COM 		ilb_comm_t	ic;
67410946SSangeeta.Misra@Sun.COM 		uint32_t	buf[ILBD_MSG_SIZE / sizeof (uint32_t)];
67510946SSangeeta.Misra@Sun.COM 	} ic_u;
67610946SSangeeta.Misra@Sun.COM 	int	rc = ILB_STATUS_OK;
67710946SSangeeta.Misra@Sun.COM 	ssize_t	r;
67810946SSangeeta.Misra@Sun.COM 
67910946SSangeeta.Misra@Sun.COM 	if (event == ILBD_EVENT_REQ) {
68010946SSangeeta.Misra@Sun.COM 		/*
68110946SSangeeta.Misra@Sun.COM 		 * Something is wrong with the client since there is a
68210946SSangeeta.Misra@Sun.COM 		 * pending reply, the client should not send us another
68310946SSangeeta.Misra@Sun.COM 		 * request.  Kill this client.
68410946SSangeeta.Misra@Sun.COM 		 */
68510946SSangeeta.Misra@Sun.COM 		if (cli->cli_saved_reply != NULL) {
68610946SSangeeta.Misra@Sun.COM 			logerr("handle_req: misbehaving client, more than one "
68710946SSangeeta.Misra@Sun.COM 			    "outstanding request");
68810946SSangeeta.Misra@Sun.COM 			rc = ILB_STATUS_INTERNAL;
68910946SSangeeta.Misra@Sun.COM 			goto err_out;
69010946SSangeeta.Misra@Sun.COM 		}
69110946SSangeeta.Misra@Sun.COM 
69210946SSangeeta.Misra@Sun.COM 		/*
69310946SSangeeta.Misra@Sun.COM 		 * Our socket is message based so we should be able
69410946SSangeeta.Misra@Sun.COM 		 * to get the request in one single read.
69510946SSangeeta.Misra@Sun.COM 		 */
69610946SSangeeta.Misra@Sun.COM 		r = recv(cli->cli_sd, (void *)ic_u.buf, sizeof (ic_u.buf), 0);
69710946SSangeeta.Misra@Sun.COM 		if (r < 0) {
69810946SSangeeta.Misra@Sun.COM 			if (errno != EINTR) {
69910946SSangeeta.Misra@Sun.COM 				logperror("handle_req: read failed");
70010946SSangeeta.Misra@Sun.COM 				rc = ILB_STATUS_READ;
70110946SSangeeta.Misra@Sun.COM 				goto err_out;
70210946SSangeeta.Misra@Sun.COM 			}
70310946SSangeeta.Misra@Sun.COM 			/*
70410946SSangeeta.Misra@Sun.COM 			 * If interrupted, just re-associate the cli_sd
70510946SSangeeta.Misra@Sun.COM 			 * with the port.
70610946SSangeeta.Misra@Sun.COM 			 */
70710946SSangeeta.Misra@Sun.COM 			goto done;
70810946SSangeeta.Misra@Sun.COM 		}
70910946SSangeeta.Misra@Sun.COM 		cli->cli_cmd = ic_u.ic.ic_cmd;
71010946SSangeeta.Misra@Sun.COM 
71110946SSangeeta.Misra@Sun.COM 		rc = consume_common_struct(&ic_u.ic, r, cli, ev_port);
71210946SSangeeta.Misra@Sun.COM 		if (rc == ILB_STATUS_EWOULDBLOCK)
71310946SSangeeta.Misra@Sun.COM 			goto blocked;
71410946SSangeeta.Misra@Sun.COM 		/* Fatal error communicating with client, free it. */
71510946SSangeeta.Misra@Sun.COM 		if (rc == ILB_STATUS_SEND)
71610946SSangeeta.Misra@Sun.COM 			goto err_out;
71710946SSangeeta.Misra@Sun.COM 	} else {
71810946SSangeeta.Misra@Sun.COM 		assert(event == ILBD_EVENT_REP_OK);
71910946SSangeeta.Misra@Sun.COM 		assert(cli->cli_saved_reply != NULL);
72010946SSangeeta.Misra@Sun.COM 
72110946SSangeeta.Misra@Sun.COM 		/*
72210946SSangeeta.Misra@Sun.COM 		 * The reply to client was previously blocked, we will
72310946SSangeeta.Misra@Sun.COM 		 * send again.
72410946SSangeeta.Misra@Sun.COM 		 */
72510946SSangeeta.Misra@Sun.COM 		if (send(cli->cli_sd, cli->cli_saved_reply,
72610946SSangeeta.Misra@Sun.COM 		    cli->cli_saved_size, 0) != cli->cli_saved_size) {
72710946SSangeeta.Misra@Sun.COM 			if (errno != EWOULDBLOCK) {
72810946SSangeeta.Misra@Sun.COM 				logdebug("handle_req: send: %s",
72910946SSangeeta.Misra@Sun.COM 				    strerror(errno));
73010946SSangeeta.Misra@Sun.COM 				rc = ILB_STATUS_SEND;
73110946SSangeeta.Misra@Sun.COM 				goto err_out;
73210946SSangeeta.Misra@Sun.COM 			}
73310946SSangeeta.Misra@Sun.COM 			goto blocked;
73410946SSangeeta.Misra@Sun.COM 		}
73510946SSangeeta.Misra@Sun.COM 		free(cli->cli_saved_reply);
73610946SSangeeta.Misra@Sun.COM 		cli->cli_saved_reply = NULL;
73710946SSangeeta.Misra@Sun.COM 		cli->cli_saved_size = 0;
73810946SSangeeta.Misra@Sun.COM 	}
73910946SSangeeta.Misra@Sun.COM done:
74010946SSangeeta.Misra@Sun.COM 	/* Re-associate with the event port for more requests. */
74110946SSangeeta.Misra@Sun.COM 	cli->cli_ev = ILBD_EVENT_REQ;
74210946SSangeeta.Misra@Sun.COM 	if (port_associate(ev_port, PORT_SOURCE_FD, cli->cli_sd,
74310946SSangeeta.Misra@Sun.COM 	    POLLRDNORM, cli) == -1) {
74410946SSangeeta.Misra@Sun.COM 		logperror("handle_req: port_associate(POLLRDNORM)");
74510946SSangeeta.Misra@Sun.COM 		rc = ILB_STATUS_INTERNAL;
74610946SSangeeta.Misra@Sun.COM 		goto err_out;
74710946SSangeeta.Misra@Sun.COM 	}
74810946SSangeeta.Misra@Sun.COM 	return;
74910946SSangeeta.Misra@Sun.COM 
75010946SSangeeta.Misra@Sun.COM blocked:
75110946SSangeeta.Misra@Sun.COM 	/* Re-associate with the event port. */
75210946SSangeeta.Misra@Sun.COM 	cli->cli_ev = ILBD_EVENT_REP_OK;
75310946SSangeeta.Misra@Sun.COM 	if (port_associate(ev_port, PORT_SOURCE_FD, cli->cli_sd, POLLWRNORM,
75410946SSangeeta.Misra@Sun.COM 	    cli) == -1) {
75510946SSangeeta.Misra@Sun.COM 		logperror("handle_req: port_associate(POLLWRNORM)");
75610946SSangeeta.Misra@Sun.COM 		rc = ILB_STATUS_INTERNAL;
75710946SSangeeta.Misra@Sun.COM 		goto err_out;
75810946SSangeeta.Misra@Sun.COM 	}
75910946SSangeeta.Misra@Sun.COM 	return;
76010946SSangeeta.Misra@Sun.COM 
76110946SSangeeta.Misra@Sun.COM err_out:
76210946SSangeeta.Misra@Sun.COM 	ilbd_free_cli(cli);
76310946SSangeeta.Misra@Sun.COM }
76410946SSangeeta.Misra@Sun.COM 
76510946SSangeeta.Misra@Sun.COM static void
i_ilbd_read_config(int ev_port)76610946SSangeeta.Misra@Sun.COM i_ilbd_read_config(int ev_port)
76710946SSangeeta.Misra@Sun.COM {
76810946SSangeeta.Misra@Sun.COM 	logdebug("i_ilbd_read_config: port %d", ev_port);
76910946SSangeeta.Misra@Sun.COM 	(void) ilbd_walk_sg_pgs(ilbd_create_sg, &ev_port, NULL);
77010946SSangeeta.Misra@Sun.COM 	(void) ilbd_walk_hc_pgs(ilbd_create_hc, &ev_port, NULL);
77110946SSangeeta.Misra@Sun.COM 	(void) ilbd_walk_rule_pgs(ilbd_create_rule, &ev_port, NULL);
77210946SSangeeta.Misra@Sun.COM }
77310946SSangeeta.Misra@Sun.COM 
77410946SSangeeta.Misra@Sun.COM /*
77510946SSangeeta.Misra@Sun.COM  * main event loop for ilbd
77610946SSangeeta.Misra@Sun.COM  * asserts that argument 'listener' is a server socket ready to accept() on.
77710946SSangeeta.Misra@Sun.COM  */
77810946SSangeeta.Misra@Sun.COM static void
main_loop(int listener)77910946SSangeeta.Misra@Sun.COM main_loop(int listener)
78010946SSangeeta.Misra@Sun.COM {
78110946SSangeeta.Misra@Sun.COM 	port_event_t		p_ev;
78210946SSangeeta.Misra@Sun.COM 	int			ev_port, ev_port_obj;
78310946SSangeeta.Misra@Sun.COM 	ilbd_event_obj_t	ev_obj;
78410946SSangeeta.Misra@Sun.COM 	ilbd_timer_event_obj_t	timer_ev_obj;
78510946SSangeeta.Misra@Sun.COM 
78610946SSangeeta.Misra@Sun.COM 	ev_port = port_create();
78710946SSangeeta.Misra@Sun.COM 	if (ev_port == -1) {
78810946SSangeeta.Misra@Sun.COM 		logperror("main_loop: port_create failed");
78910946SSangeeta.Misra@Sun.COM 		exit(-1);
79010946SSangeeta.Misra@Sun.COM 	}
79110946SSangeeta.Misra@Sun.COM 	ilbd_hc_timer_init(ev_port, &timer_ev_obj);
79210946SSangeeta.Misra@Sun.COM 
79310946SSangeeta.Misra@Sun.COM 	ev_obj.ev = ILBD_EVENT_NEW_REQ;
79410946SSangeeta.Misra@Sun.COM 	if (port_associate(ev_port, PORT_SOURCE_FD, listener, POLLRDNORM,
79510946SSangeeta.Misra@Sun.COM 	    &ev_obj) == -1) {
79610946SSangeeta.Misra@Sun.COM 		logperror("main_loop: port_associate failed");
79710946SSangeeta.Misra@Sun.COM 		exit(1);
79810946SSangeeta.Misra@Sun.COM 	}
79910946SSangeeta.Misra@Sun.COM 
80010946SSangeeta.Misra@Sun.COM 	i_ilbd_read_config(ev_port);
80110946SSangeeta.Misra@Sun.COM 	ilbd_hc_timer_update(&timer_ev_obj);
80210946SSangeeta.Misra@Sun.COM 
80310946SSangeeta.Misra@Sun.COM 	_NOTE(CONSTCOND)
80410946SSangeeta.Misra@Sun.COM 	while (B_TRUE) {
80510946SSangeeta.Misra@Sun.COM 		int r;
80610946SSangeeta.Misra@Sun.COM 		ilbd_event_t event;
80710946SSangeeta.Misra@Sun.COM 		ilbd_client_t *cli;
80810946SSangeeta.Misra@Sun.COM 
80910946SSangeeta.Misra@Sun.COM 		r = port_get(ev_port, &p_ev, NULL);
81010946SSangeeta.Misra@Sun.COM 		if (r == -1) {
81110946SSangeeta.Misra@Sun.COM 			if (errno == EINTR)
81210946SSangeeta.Misra@Sun.COM 				continue;
81310946SSangeeta.Misra@Sun.COM 			logperror("main_loop: port_get failed");
81410946SSangeeta.Misra@Sun.COM 			break;
81510946SSangeeta.Misra@Sun.COM 		}
81610946SSangeeta.Misra@Sun.COM 
81710946SSangeeta.Misra@Sun.COM 		ev_port_obj = p_ev.portev_object;
81810946SSangeeta.Misra@Sun.COM 		event = ((ilbd_event_obj_t *)p_ev.portev_user)->ev;
81910946SSangeeta.Misra@Sun.COM 
82010946SSangeeta.Misra@Sun.COM 		switch (event) {
82110946SSangeeta.Misra@Sun.COM 		case ILBD_EVENT_TIMER:
82210946SSangeeta.Misra@Sun.COM 			ilbd_hc_timeout();
82310946SSangeeta.Misra@Sun.COM 			break;
82410946SSangeeta.Misra@Sun.COM 
82510946SSangeeta.Misra@Sun.COM 		case ILBD_EVENT_PROBE:
82610946SSangeeta.Misra@Sun.COM 			ilbd_hc_probe_return(ev_port, ev_port_obj,
82710946SSangeeta.Misra@Sun.COM 			    p_ev.portev_events,
82810946SSangeeta.Misra@Sun.COM 			    (ilbd_hc_probe_event_t *)p_ev.portev_user);
82910946SSangeeta.Misra@Sun.COM 			break;
83010946SSangeeta.Misra@Sun.COM 
83110946SSangeeta.Misra@Sun.COM 		case ILBD_EVENT_NEW_REQ:
83210946SSangeeta.Misra@Sun.COM 			assert(ev_port_obj == listener);
83310946SSangeeta.Misra@Sun.COM 			/*
83410946SSangeeta.Misra@Sun.COM 			 * An error happens in the listener.  Exit
83510946SSangeeta.Misra@Sun.COM 			 * for now....
83610946SSangeeta.Misra@Sun.COM 			 */
83710946SSangeeta.Misra@Sun.COM 			if (p_ev.portev_events & (POLLHUP|POLLERR)) {
83810946SSangeeta.Misra@Sun.COM 				logerr("main_loop: listener error");
83910946SSangeeta.Misra@Sun.COM 				exit(1);
84010946SSangeeta.Misra@Sun.COM 			}
84110946SSangeeta.Misra@Sun.COM 			new_req(ev_port, ev_port_obj, &ev_obj);
84210946SSangeeta.Misra@Sun.COM 			break;
84310946SSangeeta.Misra@Sun.COM 
84410946SSangeeta.Misra@Sun.COM 		case ILBD_EVENT_REP_OK:
84510946SSangeeta.Misra@Sun.COM 		case ILBD_EVENT_REQ:
84610946SSangeeta.Misra@Sun.COM 			cli = (ilbd_client_t *)p_ev.portev_user;
84710946SSangeeta.Misra@Sun.COM 			assert(ev_port_obj == cli->cli_sd);
84810946SSangeeta.Misra@Sun.COM 
84910946SSangeeta.Misra@Sun.COM 			/*
85010946SSangeeta.Misra@Sun.COM 			 * An error happens in the newly accepted
85110946SSangeeta.Misra@Sun.COM 			 * client request.  Clean up the client.
85210946SSangeeta.Misra@Sun.COM 			 * this also happens when client closes socket,
85310946SSangeeta.Misra@Sun.COM 			 * so not necessarily a reason for alarm
85410946SSangeeta.Misra@Sun.COM 			 */
85510946SSangeeta.Misra@Sun.COM 			if (p_ev.portev_events & (POLLHUP|POLLERR)) {
85610946SSangeeta.Misra@Sun.COM 				ilbd_free_cli(cli);
85710946SSangeeta.Misra@Sun.COM 				break;
85810946SSangeeta.Misra@Sun.COM 			}
85910946SSangeeta.Misra@Sun.COM 
86010946SSangeeta.Misra@Sun.COM 			handle_req(ev_port, event, cli);
86110946SSangeeta.Misra@Sun.COM 			break;
86210946SSangeeta.Misra@Sun.COM 
86310946SSangeeta.Misra@Sun.COM 		default:
86410946SSangeeta.Misra@Sun.COM 			logerr("main_loop: unknown event %d", event);
86510946SSangeeta.Misra@Sun.COM 			exit(EXIT_FAILURE);
86610946SSangeeta.Misra@Sun.COM 			break;
86710946SSangeeta.Misra@Sun.COM 		}
86810946SSangeeta.Misra@Sun.COM 
86910946SSangeeta.Misra@Sun.COM 		ilbd_hc_timer_update(&timer_ev_obj);
87010946SSangeeta.Misra@Sun.COM 	}
87110946SSangeeta.Misra@Sun.COM }
87210946SSangeeta.Misra@Sun.COM 
87310946SSangeeta.Misra@Sun.COM static void
i_ilbd_setup_lists(void)87410946SSangeeta.Misra@Sun.COM i_ilbd_setup_lists(void)
87510946SSangeeta.Misra@Sun.COM {
87610946SSangeeta.Misra@Sun.COM 	i_setup_sg_hlist();
87710946SSangeeta.Misra@Sun.COM 	i_setup_rule_hlist();
87810946SSangeeta.Misra@Sun.COM 	i_ilbd_setup_hc_list();
87910946SSangeeta.Misra@Sun.COM }
88010946SSangeeta.Misra@Sun.COM 
88110946SSangeeta.Misra@Sun.COM /*
88210946SSangeeta.Misra@Sun.COM  * Usage message - call only during startup. it will print its
88310946SSangeeta.Misra@Sun.COM  * message on stderr and exit
88410946SSangeeta.Misra@Sun.COM  */
88510946SSangeeta.Misra@Sun.COM static void
Usage(char * name)88610946SSangeeta.Misra@Sun.COM Usage(char *name)
88710946SSangeeta.Misra@Sun.COM {
88810946SSangeeta.Misra@Sun.COM 	(void) fprintf(stderr, gettext("Usage: %s [-d|--debug]\n"), name);
88910946SSangeeta.Misra@Sun.COM 	exit(1);
89010946SSangeeta.Misra@Sun.COM }
89110946SSangeeta.Misra@Sun.COM 
89210946SSangeeta.Misra@Sun.COM static void
print_version(char * name)89310946SSangeeta.Misra@Sun.COM print_version(char *name)
89410946SSangeeta.Misra@Sun.COM {
89510946SSangeeta.Misra@Sun.COM 	(void) printf("%s %s\n", basename(name), ILBD_VERSION);
89610946SSangeeta.Misra@Sun.COM 	(void) printf(gettext(ILBD_COPYRIGHT));
89710946SSangeeta.Misra@Sun.COM 	exit(0);
89810946SSangeeta.Misra@Sun.COM }
89910946SSangeeta.Misra@Sun.COM 
90010946SSangeeta.Misra@Sun.COM /*
90110946SSangeeta.Misra@Sun.COM  * Increase the file descriptor limit for handling a lot of health check
90210946SSangeeta.Misra@Sun.COM  * processes (each requires a pipe).
90310946SSangeeta.Misra@Sun.COM  *
90410946SSangeeta.Misra@Sun.COM  * Note that this function is called before ilbd becomes a daemon.  So
90510946SSangeeta.Misra@Sun.COM  * we call perror(3C) to print out error message directly so that SMF
90610946SSangeeta.Misra@Sun.COM  * can catch them.
90710946SSangeeta.Misra@Sun.COM  */
90810946SSangeeta.Misra@Sun.COM static void
set_rlim(void)90910946SSangeeta.Misra@Sun.COM set_rlim(void)
91010946SSangeeta.Misra@Sun.COM {
91110946SSangeeta.Misra@Sun.COM 	struct rlimit rlp;
91210946SSangeeta.Misra@Sun.COM 
91310946SSangeeta.Misra@Sun.COM 	if (getrlimit(RLIMIT_NOFILE, &rlp) == -1) {
91410946SSangeeta.Misra@Sun.COM 		perror("ilbd: getrlimit");
91510946SSangeeta.Misra@Sun.COM 		exit(errno);
91610946SSangeeta.Misra@Sun.COM 	}
91710946SSangeeta.Misra@Sun.COM 	rlp.rlim_cur = rlp.rlim_max;
91810946SSangeeta.Misra@Sun.COM 	if (setrlimit(RLIMIT_NOFILE, &rlp) == -1) {
91910946SSangeeta.Misra@Sun.COM 		perror("ilbd: setrlimit");
92010946SSangeeta.Misra@Sun.COM 		exit(errno);
92110946SSangeeta.Misra@Sun.COM 	}
92210946SSangeeta.Misra@Sun.COM }
92310946SSangeeta.Misra@Sun.COM 
92410946SSangeeta.Misra@Sun.COM int
main(int argc,char ** argv)92510946SSangeeta.Misra@Sun.COM main(int argc, char **argv)
92610946SSangeeta.Misra@Sun.COM {
92710946SSangeeta.Misra@Sun.COM 	int	s;
92810946SSangeeta.Misra@Sun.COM 	int	c;
92910946SSangeeta.Misra@Sun.COM 
93010946SSangeeta.Misra@Sun.COM 	(void) setlocale(LC_ALL, "");
93110946SSangeeta.Misra@Sun.COM #if !defined(TEXT_DOMAIN)
93210946SSangeeta.Misra@Sun.COM #define	TEXT_DOMAIN "SYS_TEST"
93310946SSangeeta.Misra@Sun.COM #endif
93410946SSangeeta.Misra@Sun.COM 	static const char daemon_dir[] = DAEMON_DIR;
93510946SSangeeta.Misra@Sun.COM 
93610946SSangeeta.Misra@Sun.COM 	(void) textdomain(TEXT_DOMAIN);
93710946SSangeeta.Misra@Sun.COM 
93810946SSangeeta.Misra@Sun.COM 	while ((c = getopt(argc, argv, ":V?d(debug)")) != -1) {
93910946SSangeeta.Misra@Sun.COM 		switch ((char)c) {
94010946SSangeeta.Misra@Sun.COM 		case '?': Usage(argv[0]);
94110946SSangeeta.Misra@Sun.COM 			/* not reached */
94210946SSangeeta.Misra@Sun.COM 			break;
94310946SSangeeta.Misra@Sun.COM 		case 'V': print_version(argv[0]);
94410946SSangeeta.Misra@Sun.COM 			/* not reached */
94510946SSangeeta.Misra@Sun.COM 			break;
94610946SSangeeta.Misra@Sun.COM 		case 'd': ilbd_enable_debug();
94710946SSangeeta.Misra@Sun.COM 			break;
94810946SSangeeta.Misra@Sun.COM 		default: Usage(argv[0]);
94910946SSangeeta.Misra@Sun.COM 			/* not reached */
95010946SSangeeta.Misra@Sun.COM 			break;
95110946SSangeeta.Misra@Sun.COM 		}
95210946SSangeeta.Misra@Sun.COM 	}
95310946SSangeeta.Misra@Sun.COM 
95410946SSangeeta.Misra@Sun.COM 	/*
95510946SSangeeta.Misra@Sun.COM 	 * Whenever the daemon starts, it needs to start with a clean
95610946SSangeeta.Misra@Sun.COM 	 * slate in the kernel. We need sys_ip_config privilege for
95710946SSangeeta.Misra@Sun.COM 	 * this.
95810946SSangeeta.Misra@Sun.COM 	 */
95910946SSangeeta.Misra@Sun.COM 	ilbd_reset_kernel_state();
96010946SSangeeta.Misra@Sun.COM 
96110946SSangeeta.Misra@Sun.COM 	/* Increase the limit on the number of file descriptors. */
96210946SSangeeta.Misra@Sun.COM 	set_rlim();
96310946SSangeeta.Misra@Sun.COM 
96410946SSangeeta.Misra@Sun.COM 	/*
96510946SSangeeta.Misra@Sun.COM 	 * ilbd daemon starts off as root, just so it can create
96610946SSangeeta.Misra@Sun.COM 	 * /var/run/daemon if one does not exist. After that is done
96710946SSangeeta.Misra@Sun.COM 	 * the daemon switches to "daemon" uid. This is similar to what
96810946SSangeeta.Misra@Sun.COM 	 * rpcbind does.
96910946SSangeeta.Misra@Sun.COM 	 */
97010946SSangeeta.Misra@Sun.COM 	if (mkdir(daemon_dir, DAEMON_DIR_MODE) == 0 || errno == EEXIST) {
97110946SSangeeta.Misra@Sun.COM 		(void) chmod(daemon_dir, DAEMON_DIR_MODE);
97210946SSangeeta.Misra@Sun.COM 		(void) chown(daemon_dir, DAEMON_UID, DAEMON_GID);
97310946SSangeeta.Misra@Sun.COM 	} else {
97410946SSangeeta.Misra@Sun.COM 		perror("main: mkdir failed");
97510946SSangeeta.Misra@Sun.COM 		exit(errno);
97610946SSangeeta.Misra@Sun.COM 	}
97710946SSangeeta.Misra@Sun.COM 	/*
97810946SSangeeta.Misra@Sun.COM 	 * Now lets switch ilbd as uid = daemon, gid = daemon with a
97910946SSangeeta.Misra@Sun.COM 	 * trimmed down privilege set
98010946SSangeeta.Misra@Sun.COM 	 */
98110946SSangeeta.Misra@Sun.COM 	if (__init_daemon_priv(PU_RESETGROUPS | PU_LIMITPRIVS | PU_INHERITPRIVS,
98210946SSangeeta.Misra@Sun.COM 	    DAEMON_UID, DAEMON_GID, PRIV_PROC_OWNER, PRIV_PROC_AUDIT,
98310946SSangeeta.Misra@Sun.COM 	    PRIV_NET_ICMPACCESS, PRIV_SYS_IP_CONFIG, NULL) == -1) {
98410946SSangeeta.Misra@Sun.COM 		(void) fprintf(stderr, "Insufficient privileges\n");
98510946SSangeeta.Misra@Sun.COM 		exit(EXIT_FAILURE);
98610946SSangeeta.Misra@Sun.COM 	}
98710946SSangeeta.Misra@Sun.COM 
98810946SSangeeta.Misra@Sun.COM 	/*
98910946SSangeeta.Misra@Sun.COM 	 * Opens a PF_UNIX socket to the client. No privilege needed
99010946SSangeeta.Misra@Sun.COM 	 * for this.
99110946SSangeeta.Misra@Sun.COM 	 */
99210946SSangeeta.Misra@Sun.COM 	s = ilbd_create_client_socket();
99310946SSangeeta.Misra@Sun.COM 
99410946SSangeeta.Misra@Sun.COM 	/*
99510946SSangeeta.Misra@Sun.COM 	 * Daemonify if ilbd is not running with -d option
99610946SSangeeta.Misra@Sun.COM 	 * Need proc_fork privilege for this
99710946SSangeeta.Misra@Sun.COM 	 */
99810946SSangeeta.Misra@Sun.COM 	if (!is_debugging_on()) {
99910946SSangeeta.Misra@Sun.COM 		logdebug("daemonizing...");
100010946SSangeeta.Misra@Sun.COM 		if (daemon(0, 0) != 0) {
100110946SSangeeta.Misra@Sun.COM 			logperror("daemon failed");
100210946SSangeeta.Misra@Sun.COM 			exit(EXIT_FAILURE);
100310946SSangeeta.Misra@Sun.COM 		}
100410946SSangeeta.Misra@Sun.COM 	}
100510946SSangeeta.Misra@Sun.COM 	(void) priv_set(PRIV_OFF, PRIV_INHERITABLE, PRIV_PROC_OWNER,
100610946SSangeeta.Misra@Sun.COM 	    PRIV_PROC_AUDIT, NULL);
100710946SSangeeta.Misra@Sun.COM 
100810946SSangeeta.Misra@Sun.COM 	/* if daemonified then set up syslog */
100910946SSangeeta.Misra@Sun.COM 	if (!is_debugging_on())
101010946SSangeeta.Misra@Sun.COM 		openlog("ilbd", LOG_PID, LOG_DAEMON);
101110946SSangeeta.Misra@Sun.COM 
101210946SSangeeta.Misra@Sun.COM 	i_ilbd_setup_lists();
101310946SSangeeta.Misra@Sun.COM 
101410946SSangeeta.Misra@Sun.COM 	main_loop(s);
101510946SSangeeta.Misra@Sun.COM 
101610946SSangeeta.Misra@Sun.COM 	/*
101710946SSangeeta.Misra@Sun.COM 	 * if we come here, then we experienced an error or a shutdown
101810946SSangeeta.Misra@Sun.COM 	 * indicator, so clean up after ourselves.
101910946SSangeeta.Misra@Sun.COM 	 */
102010946SSangeeta.Misra@Sun.COM 	logdebug("main(): terminating");
102110946SSangeeta.Misra@Sun.COM 
102210946SSangeeta.Misra@Sun.COM 	(void) remove(SOCKET_PATH);
102310946SSangeeta.Misra@Sun.COM 	ilbd_reset_kernel_state();
102410946SSangeeta.Misra@Sun.COM 
102510946SSangeeta.Misra@Sun.COM 	return (0);
102610946SSangeeta.Misra@Sun.COM }
1027