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