1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#include <stdio.h>
28#include <stdlib.h>
29#include <strings.h>
30#include <unistd.h>
31#include <stropts.h>
32#include <sys/types.h>
33#include <sys/socket.h>
34#include <sys/stropts.h>
35#include <sys/sockio.h>
36#include <errno.h>
37#include <sys/list.h>
38#include <auth_attr.h>
39#include <auth_list.h>
40#include <secdb.h>
41#include <libilb.h>
42#include "libilb_impl.h"
43#include "ilbd.h"
44
45/*
46 * logs error messages, either to stderr or syslog, depending on
47 * the -d option
48 */
49static boolean_t	ilbd_debugging = B_FALSE;
50
51/* Socket to issue ioctl() to the kernel */
52static	int	ksock = -1;
53
54void
55ilbd_enable_debug(void)
56{
57	ilbd_debugging = B_TRUE;
58}
59
60boolean_t
61is_debugging_on(void)
62{
63	return (ilbd_debugging);
64}
65
66/*
67 * All routines log to syslog, unless the daemon is running in
68 * the foreground, in which case the logging goes to stderr.
69 * The following logging functions are available:
70 *
71 *
72 *      logdebug(): A printf-like function for outputting debug messages
73 *      (messages at LOG_DEBUG) that are only of use to developers.
74 *
75 *      logerr(): A printf-like function for outputting error messages
76 *      (messages at LOG_ERR) from the daemon.
77 *
78 *      logperror*(): A set of functions used to output error messages
79 *      (messages at LOG_ERR); these automatically append strerror(errno)
80 *      and a newline to the message passed to them.
81 *
82 * NOTE: since the logging functions write to syslog, the messages passed
83 *      to them are not eligible for localization.  Thus, gettext() must
84 *      *not* be used.
85 *
86 */
87/* PRINTFLIKE2 */
88void
89ilbd_log(int pri, const char *fmt, ...)
90{
91	va_list ap;
92	va_start(ap, fmt);
93
94	if (ilbd_debugging == B_TRUE) {
95		(void) vfprintf(stderr, fmt, ap);
96		(void) fprintf(stderr, "\n");
97	} else {
98		vsyslog(pri, fmt, ap);
99	}
100	va_end(ap);
101
102}
103
104/* PRINTFLIKE1 */
105void
106logperror(const char *str)
107{
108	if (ilbd_debugging == B_TRUE)
109		(void) fprintf(stderr, "%s: %s\n", str, strerror(errno));
110	else
111		syslog(LOG_ERR, "%s: %m", str);
112}
113
114
115ilb_status_t
116ilbd_check_client_config_auth(const struct passwd *pwd)
117{
118	if (chkauthattr(NET_ILB_CONFIG_AUTH, pwd->pw_name) == 0) {
119		logdebug("user %s is not authorized for"
120		    " configuration operation", pwd->pw_name);
121		return (ILB_STATUS_CFGAUTH);
122	}
123	return (ILB_STATUS_OK);
124
125}
126
127ilb_status_t
128ilbd_check_client_enable_auth(const struct passwd *pwd)
129{
130	if (chkauthattr(NET_ILB_ENABLE_AUTH, pwd->pw_name) == 0) {
131		logdebug("user %s is not authorized for"
132		    " enable/disable operation", pwd->pw_name);
133		return (ILB_STATUS_CFGAUTH);
134	}
135	return (ILB_STATUS_OK);
136
137}
138
139/*
140 * input param. "err" should be one of the errnos defined in
141 * /usr/include/sys/errno.h
142 * this list is NOT complete.
143 */
144ilb_status_t
145ilb_map_errno2ilbstat(int err)
146{
147	ilb_status_t	rc = ILB_STATUS_INTERNAL;
148
149	switch (err) {
150	case 0:
151		rc = ILB_STATUS_OK; /* for completeness' sake */
152		break;
153	case EINVAL:
154		rc = ILB_STATUS_EINVAL;
155		break;
156	case ENOENT:
157		rc = ILB_STATUS_ENOENT;
158		break;
159	case ENOMEM:
160		rc = ILB_STATUS_ENOMEM;
161		break;
162	case EINPROGRESS:
163		rc = ILB_STATUS_INPROGRESS;
164		break;
165	case EEXIST:
166		rc = ILB_STATUS_EEXIST;
167		break;
168	}
169	return (rc);
170}
171
172static int
173i_get_kcmd_sz(void *cmdp)
174{
175	int		sz;
176
177	switch (((ilb_rule_cmd_t *)cmdp)->cmd) {
178	case ILB_DESTROY_RULE:
179	case ILB_ENABLE_RULE:
180	case ILB_DISABLE_RULE:
181		sz = sizeof (ilb_name_cmd_t);
182		break;
183	case ILB_CREATE_RULE:
184	case ILB_LIST_RULE:
185		sz = sizeof (ilb_rule_cmd_t);
186		break;
187	case ILB_NUM_RULES:
188		sz = sizeof (ilb_num_rules_cmd_t);
189		break;
190	case ILB_NUM_SERVERS:
191		sz = sizeof (ilb_num_servers_cmd_t);
192		break;
193	case ILB_ADD_SERVERS: {
194		ilb_servers_info_cmd_t *kcmd = (ilb_servers_info_cmd_t *)cmdp;
195
196		sz = sizeof (*kcmd) + ((kcmd->num_servers - 1) *
197		    sizeof (kcmd->servers));
198		break;
199	}
200	case ILB_RULE_NAMES: {
201		ilb_rule_names_cmd_t *kcmd = (ilb_rule_names_cmd_t *)cmdp;
202
203		sz = sizeof (*kcmd) +
204		    ((kcmd->num_names - 1) * sizeof (kcmd->buf));
205		break;
206	}
207	case ILB_DEL_SERVERS:
208	case ILB_ENABLE_SERVERS:
209	case ILB_DISABLE_SERVERS: {
210		ilb_servers_cmd_t *kcmd = (ilb_servers_cmd_t *)cmdp;
211
212		sz = sizeof (*kcmd) +
213		    ((kcmd->num_servers - 1) * sizeof (kcmd->servers));
214		break;
215	}
216	default: sz = -1;
217		break;
218	}
219	return (sz);
220}
221
222/*
223 * parameter 'sz' is optional (indicated by == 0); if it's not set
224 * we try to derive it from cmdp->cmd
225 */
226ilb_status_t
227do_ioctl(void *cmdp, ssize_t sz)
228{
229	struct strioctl	ioc;
230	int		i_rc;
231
232	if (ksock == -1) {
233		ksock = socket(AF_INET, SOCK_DGRAM, 0);
234		if (ksock == -1) {
235			logperror("do_ioctl: AF_INET socket call"
236			    "  failed");
237			return (ILB_STATUS_INTERNAL);
238		}
239	}
240
241	(void) memset(&ioc, 0, sizeof (ioc));
242	ioc.ic_cmd = SIOCILB;
243	ioc.ic_timout = 0;
244	ioc.ic_dp = cmdp;
245
246	if (sz == 0) {
247		sz = i_get_kcmd_sz(cmdp);
248
249		if (sz == -1) {
250			logdebug("do_ioctl: unknown command");
251			return (ILB_STATUS_INVAL_CMD);
252		}
253	}
254
255	ioc.ic_len = sz;
256
257	i_rc = ioctl(ksock, I_STR, (caddr_t)&ioc);
258	if (i_rc == -1) {
259		logdebug("do_ioctl: SIOCILB ioctl (%d) failed: %s",
260		    *(ilb_cmd_t *)cmdp, strerror(errno));
261		return (ilb_map_errno2ilbstat(errno));
262	}
263
264	return (ILB_STATUS_OK);
265}
266
267/*
268 * Create an OK reply to a client request.  It is assumed that the passed
269 * in buffer is large enough to hold the reply.
270 */
271void
272ilbd_reply_ok(uint32_t *rbuf, size_t *rbufsz)
273{
274	ilb_comm_t *ic = (ilb_comm_t *)rbuf;
275
276	ic->ic_cmd = ILBD_CMD_OK;
277	/* Default is one exchange of request/response. */
278	ic->ic_flags = ILB_COMM_END;
279	*rbufsz = sizeof (ilb_comm_t);
280}
281
282/*
283 * Create an error reply to a client request.  It is assumed that the passed
284 * in buffer is large enough to hold the reply.
285 */
286void
287ilbd_reply_err(uint32_t *rbuf, size_t *rbufsz, ilb_status_t status)
288{
289	ilb_comm_t *ic = (ilb_comm_t *)rbuf;
290
291	ic->ic_cmd = ILBD_CMD_ERROR;
292	/* Default is one exchange of request/response. */
293	ic->ic_flags = ILB_COMM_END;
294	*(ilb_status_t *)&ic->ic_data = status;
295	*rbufsz = sizeof (ilb_comm_t) + sizeof (ilb_status_t);
296}
297