1/* 2 * Copyright (c) 2005-2007 Voltaire, Inc. All rights reserved. 3 * Copyright (c) 2008 HNR Consulting. All rights reserved. 4 * 5 * This software is available to you under a choice of one of two 6 * licenses. You may choose to be licensed under the terms of the GNU 7 * General Public License (GPL) Version 2, available from the file 8 * COPYING in the main directory of this source tree, or the 9 * OpenIB.org BSD license below: 10 * 11 * Redistribution and use in source and binary forms, with or 12 * without modification, are permitted provided that the following 13 * conditions are met: 14 * 15 * - Redistributions of source code must retain the above 16 * copyright notice, this list of conditions and the following 17 * disclaimer. 18 * 19 * - Redistributions in binary form must reproduce the above 20 * copyright notice, this list of conditions and the following 21 * disclaimer in the documentation and/or other materials 22 * provided with the distribution. 23 * 24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 28 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 29 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31 * SOFTWARE. 32 * 33 */ 34 35/* 36 * Abstract: 37 * Provide a framework for the Console which decouples the connection 38 * or I/O from the functionality, or commands. 39 * 40 * Extensible - allows a variety of connection methods independent of 41 * the console commands. 42 */ 43 44#if HAVE_CONFIG_H 45# include <config.h> 46#endif /* HAVE_CONFIG_H */ 47 48#define _GNU_SOURCE /* for getline */ 49#ifdef ENABLE_OSM_CONSOLE_SOCKET 50#include <tcpd.h> 51#include <arpa/inet.h> 52#include <netinet/in.h> 53#include <sys/socket.h> 54#endif 55#include <unistd.h> 56#include <errno.h> 57#include <signal.h> 58#include <opensm/osm_console_io.h> 59 60static int is_local(char *str) 61{ 62 // convenience - checks if just stdin/stdout 63 if (str) 64 return (strcmp(str, OSM_LOCAL_CONSOLE) == 0); 65 return 0; 66} 67 68static int is_loopback(char *str) 69{ 70 // convenience - checks if socket based connection 71 if (str) 72 return (strcmp(str, OSM_LOOPBACK_CONSOLE) == 0); 73 return 0; 74} 75 76static int is_remote(char *str) 77{ 78 // convenience - checks if socket based connection 79 if (str) 80 return (strcmp(str, OSM_REMOTE_CONSOLE) == 0) 81 || is_loopback(str); 82 return 0; 83} 84 85int is_console_enabled(osm_subn_opt_t * p_opt) 86{ 87 // checks for a variety of types of consoles - default is off or 0 88 if (p_opt) 89 return (is_local(p_opt->console) 90 || is_loopback(p_opt->console) 91 || is_remote(p_opt->console)); 92 return 0; 93} 94 95 96#ifdef ENABLE_OSM_CONSOLE_SOCKET 97static int cio_close(osm_console_t * p_oct) 98{ 99 int rtnval = -1; 100 if (p_oct && (p_oct->in_fd > 0)) { 101 rtnval = close(p_oct->in_fd); 102 p_oct->in_fd = -1; 103 p_oct->out_fd = -1; 104 p_oct->in = NULL; 105 p_oct->out = NULL; 106 } 107 return rtnval; 108} 109#endif 110 111/* close the connection */ 112static void osm_console_close(osm_console_t * p_oct, osm_log_t * p_log) 113{ 114#ifdef ENABLE_OSM_CONSOLE_SOCKET 115 if ((p_oct->socket > 0) && (p_oct->in_fd != -1)) { 116 OSM_LOG(p_log, OSM_LOG_INFO, 117 "Console connection closed: %s (%s)\n", 118 p_oct->client_hn, p_oct->client_ip); 119 cio_close(p_oct); 120 } 121 if (p_oct->socket > 0) { 122 close(p_oct->socket); 123 p_oct->socket = -1; 124 } 125#endif 126} 127 128 129/********************************************************************** 130 * Do authentication & authorization check 131 **********************************************************************/ 132#ifdef ENABLE_OSM_CONSOLE_SOCKET 133int is_authorized(osm_console_t * p_oct) 134{ 135 /* allowed to use the console? */ 136 p_oct->authorized = !is_remote(p_oct->client_type) || 137 hosts_ctl(OSM_DAEMON_NAME, p_oct->client_hn, p_oct->client_ip, 138 "STRING_UNKNOWN"); 139 return p_oct->authorized; 140} 141#endif 142 143void osm_console_prompt(FILE * out) 144{ 145 if (out) { 146 fprintf(out, "OpenSM %s", OSM_COMMAND_PROMPT); 147 fflush(out); 148 } 149} 150 151int osm_console_init(osm_subn_opt_t * opt, osm_console_t * p_oct, osm_log_t * p_log) 152{ 153 p_oct->socket = -1; 154 strncpy(p_oct->client_type, opt->console, sizeof(p_oct->client_type)); 155 156 /* set up the file descriptors for the console */ 157 if (strcmp(opt->console, OSM_LOCAL_CONSOLE) == 0) { 158 p_oct->in = stdin; 159 p_oct->out = stdout; 160 p_oct->in_fd = fileno(stdin); 161 p_oct->out_fd = fileno(stdout); 162 163 osm_console_prompt(p_oct->out); 164#ifdef ENABLE_OSM_CONSOLE_SOCKET 165 } else if (strcmp(opt->console, OSM_REMOTE_CONSOLE) == 0 166 || strcmp(opt->console, OSM_LOOPBACK_CONSOLE) == 0) { 167 struct sockaddr_in sin; 168 int optval = 1; 169 170 if ((p_oct->socket = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 171 OSM_LOG(p_log, OSM_LOG_ERROR, 172 "ERR 4B01: Failed to open console socket: %s\n", 173 strerror(errno)); 174 return -1; 175 } 176 setsockopt(p_oct->socket, SOL_SOCKET, SO_REUSEADDR, 177 &optval, sizeof(optval)); 178 sin.sin_family = AF_INET; 179 sin.sin_port = htons(opt->console_port); 180 if (strcmp(opt->console, OSM_REMOTE_CONSOLE) == 0) 181 sin.sin_addr.s_addr = htonl(INADDR_ANY); 182 else 183 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 184 if (bind(p_oct->socket, &sin, sizeof(sin)) < 0) { 185 OSM_LOG(p_log, OSM_LOG_ERROR, 186 "ERR 4B02: Failed to bind console socket: %s\n", 187 strerror(errno)); 188 return -1; 189 } 190 if (listen(p_oct->socket, 1) < 0) { 191 OSM_LOG(p_log, OSM_LOG_ERROR, 192 "ERR 4B03: Failed to listen on socket: %s\n", 193 strerror(errno)); 194 return -1; 195 } 196 197 signal(SIGPIPE, SIG_IGN); /* protect ourselves from closed pipes */ 198 p_oct->in = NULL; 199 p_oct->out = NULL; 200 p_oct->in_fd = -1; 201 p_oct->out_fd = -1; 202 OSM_LOG(p_log, OSM_LOG_INFO, 203 "Console listening on port %d\n", opt->console_port); 204#endif 205 } 206 207 return 0; 208} 209 210/* clean up and release resources */ 211void osm_console_exit(osm_console_t * p_oct, osm_log_t * p_log) 212{ 213 // clean up and release resources, currently just close the socket 214 osm_console_close(p_oct, p_log); 215} 216 217#ifdef ENABLE_OSM_CONSOLE_SOCKET 218int cio_open(osm_console_t * p_oct, int new_fd, osm_log_t * p_log) 219{ 220 // returns zero if opened fine, -1 otherwise 221 char *p_line; 222 size_t len; 223 ssize_t n; 224 225 if (p_oct->in_fd >= 0) { 226 FILE *file = fdopen(new_fd, "w+"); 227 228 fprintf(file, "OpenSM Console connection already in use\n" 229 " kill other session (y/n)? "); 230 fflush(file); 231 p_line = NULL; 232 n = getline(&p_line, &len, file); 233 if (n > 0 && (p_line[0] == 'y' || p_line[0] == 'Y')) { 234 osm_console_close(p_oct, p_log); 235 } else { 236 OSM_LOG(p_log, OSM_LOG_INFO, 237 "Console connection aborted: %s (%s)\n", 238 p_oct->client_hn, p_oct->client_ip); 239 close(new_fd); 240 return -1; 241 } 242 } 243 p_oct->in_fd = new_fd; 244 p_oct->out_fd = p_oct->in_fd; 245 p_oct->in = fdopen(p_oct->in_fd, "w+"); 246 p_oct->out = p_oct->in; 247 osm_console_prompt(p_oct->out); 248 OSM_LOG(p_log, OSM_LOG_INFO, 249 "Console connection accepted: %s (%s)\n", 250 p_oct->client_hn, p_oct->client_ip); 251 252 return (p_oct->in == NULL) ? -1 : 0; 253} 254#endif 255