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 */ 49 static boolean_t ilbd_debugging = B_FALSE; 50 51 /* Socket to issue ioctl() to the kernel */ 52 static int ksock = -1; 53 54 void 55 ilbd_enable_debug(void) 56 { 57 ilbd_debugging = B_TRUE; 58 } 59 60 boolean_t 61 is_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 */ 88 void 89 ilbd_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 */ 105 void 106 logperror(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 115 ilb_status_t 116 ilbd_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 127 ilb_status_t 128 ilbd_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 */ 144 ilb_status_t 145 ilb_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 172 static int 173 i_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 */ 226 ilb_status_t 227 do_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 */ 271 void 272 ilbd_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 */ 286 void 287 ilbd_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