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