1219820Sjeff/* 2219820Sjeff * Copyright (c) 2005-2007 Voltaire, Inc. All rights reserved. 3219820Sjeff * Copyright (c) 2008 HNR Consulting. All rights reserved. 4219820Sjeff * 5219820Sjeff * This software is available to you under a choice of one of two 6219820Sjeff * licenses. You may choose to be licensed under the terms of the GNU 7219820Sjeff * General Public License (GPL) Version 2, available from the file 8219820Sjeff * COPYING in the main directory of this source tree, or the 9219820Sjeff * OpenIB.org BSD license below: 10219820Sjeff * 11219820Sjeff * Redistribution and use in source and binary forms, with or 12219820Sjeff * without modification, are permitted provided that the following 13219820Sjeff * conditions are met: 14219820Sjeff * 15219820Sjeff * - Redistributions of source code must retain the above 16219820Sjeff * copyright notice, this list of conditions and the following 17219820Sjeff * disclaimer. 18219820Sjeff * 19219820Sjeff * - Redistributions in binary form must reproduce the above 20219820Sjeff * copyright notice, this list of conditions and the following 21219820Sjeff * disclaimer in the documentation and/or other materials 22219820Sjeff * provided with the distribution. 23219820Sjeff * 24219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 27219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 28219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 29219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 30219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31219820Sjeff * SOFTWARE. 32219820Sjeff * 33219820Sjeff */ 34219820Sjeff 35219820Sjeff/* 36219820Sjeff * Abstract: 37219820Sjeff * Provide a framework for the Console which decouples the connection 38219820Sjeff * or I/O from the functionality, or commands. 39219820Sjeff * 40219820Sjeff * Extensible - allows a variety of connection methods independent of 41219820Sjeff * the console commands. 42219820Sjeff */ 43219820Sjeff 44219820Sjeff#if HAVE_CONFIG_H 45219820Sjeff# include <config.h> 46219820Sjeff#endif /* HAVE_CONFIG_H */ 47219820Sjeff 48219820Sjeff#define _GNU_SOURCE /* for getline */ 49219820Sjeff#ifdef ENABLE_OSM_CONSOLE_SOCKET 50219820Sjeff#include <tcpd.h> 51219820Sjeff#include <arpa/inet.h> 52219820Sjeff#include <netinet/in.h> 53219820Sjeff#include <sys/socket.h> 54219820Sjeff#endif 55219820Sjeff#include <unistd.h> 56219820Sjeff#include <errno.h> 57219820Sjeff#include <signal.h> 58219820Sjeff#include <opensm/osm_console_io.h> 59219820Sjeff 60219820Sjeffstatic int is_local(char *str) 61219820Sjeff{ 62219820Sjeff // convenience - checks if just stdin/stdout 63219820Sjeff if (str) 64219820Sjeff return (strcmp(str, OSM_LOCAL_CONSOLE) == 0); 65219820Sjeff return 0; 66219820Sjeff} 67219820Sjeff 68219820Sjeffstatic int is_loopback(char *str) 69219820Sjeff{ 70219820Sjeff // convenience - checks if socket based connection 71219820Sjeff if (str) 72219820Sjeff return (strcmp(str, OSM_LOOPBACK_CONSOLE) == 0); 73219820Sjeff return 0; 74219820Sjeff} 75219820Sjeff 76219820Sjeffstatic int is_remote(char *str) 77219820Sjeff{ 78219820Sjeff // convenience - checks if socket based connection 79219820Sjeff if (str) 80219820Sjeff return (strcmp(str, OSM_REMOTE_CONSOLE) == 0) 81219820Sjeff || is_loopback(str); 82219820Sjeff return 0; 83219820Sjeff} 84219820Sjeff 85219820Sjeffint is_console_enabled(osm_subn_opt_t * p_opt) 86219820Sjeff{ 87219820Sjeff // checks for a variety of types of consoles - default is off or 0 88219820Sjeff if (p_opt) 89219820Sjeff return (is_local(p_opt->console) 90219820Sjeff || is_loopback(p_opt->console) 91219820Sjeff || is_remote(p_opt->console)); 92219820Sjeff return 0; 93219820Sjeff} 94219820Sjeff 95219820Sjeff 96219820Sjeff#ifdef ENABLE_OSM_CONSOLE_SOCKET 97219820Sjeffstatic int cio_close(osm_console_t * p_oct) 98219820Sjeff{ 99219820Sjeff int rtnval = -1; 100219820Sjeff if (p_oct && (p_oct->in_fd > 0)) { 101219820Sjeff rtnval = close(p_oct->in_fd); 102219820Sjeff p_oct->in_fd = -1; 103219820Sjeff p_oct->out_fd = -1; 104219820Sjeff p_oct->in = NULL; 105219820Sjeff p_oct->out = NULL; 106219820Sjeff } 107219820Sjeff return rtnval; 108219820Sjeff} 109219820Sjeff#endif 110219820Sjeff 111219820Sjeff/* close the connection */ 112219820Sjeffstatic void osm_console_close(osm_console_t * p_oct, osm_log_t * p_log) 113219820Sjeff{ 114219820Sjeff#ifdef ENABLE_OSM_CONSOLE_SOCKET 115219820Sjeff if ((p_oct->socket > 0) && (p_oct->in_fd != -1)) { 116219820Sjeff OSM_LOG(p_log, OSM_LOG_INFO, 117219820Sjeff "Console connection closed: %s (%s)\n", 118219820Sjeff p_oct->client_hn, p_oct->client_ip); 119219820Sjeff cio_close(p_oct); 120219820Sjeff } 121219820Sjeff if (p_oct->socket > 0) { 122219820Sjeff close(p_oct->socket); 123219820Sjeff p_oct->socket = -1; 124219820Sjeff } 125219820Sjeff#endif 126219820Sjeff} 127219820Sjeff 128219820Sjeff 129219820Sjeff/********************************************************************** 130219820Sjeff * Do authentication & authorization check 131219820Sjeff **********************************************************************/ 132219820Sjeff#ifdef ENABLE_OSM_CONSOLE_SOCKET 133219820Sjeffint is_authorized(osm_console_t * p_oct) 134219820Sjeff{ 135219820Sjeff /* allowed to use the console? */ 136219820Sjeff p_oct->authorized = !is_remote(p_oct->client_type) || 137219820Sjeff hosts_ctl(OSM_DAEMON_NAME, p_oct->client_hn, p_oct->client_ip, 138219820Sjeff "STRING_UNKNOWN"); 139219820Sjeff return p_oct->authorized; 140219820Sjeff} 141219820Sjeff#endif 142219820Sjeff 143219820Sjeffvoid osm_console_prompt(FILE * out) 144219820Sjeff{ 145219820Sjeff if (out) { 146219820Sjeff fprintf(out, "OpenSM %s", OSM_COMMAND_PROMPT); 147219820Sjeff fflush(out); 148219820Sjeff } 149219820Sjeff} 150219820Sjeff 151219820Sjeffint osm_console_init(osm_subn_opt_t * opt, osm_console_t * p_oct, osm_log_t * p_log) 152219820Sjeff{ 153219820Sjeff p_oct->socket = -1; 154219820Sjeff strncpy(p_oct->client_type, opt->console, sizeof(p_oct->client_type)); 155219820Sjeff 156219820Sjeff /* set up the file descriptors for the console */ 157219820Sjeff if (strcmp(opt->console, OSM_LOCAL_CONSOLE) == 0) { 158219820Sjeff p_oct->in = stdin; 159219820Sjeff p_oct->out = stdout; 160219820Sjeff p_oct->in_fd = fileno(stdin); 161219820Sjeff p_oct->out_fd = fileno(stdout); 162219820Sjeff 163219820Sjeff osm_console_prompt(p_oct->out); 164219820Sjeff#ifdef ENABLE_OSM_CONSOLE_SOCKET 165219820Sjeff } else if (strcmp(opt->console, OSM_REMOTE_CONSOLE) == 0 166219820Sjeff || strcmp(opt->console, OSM_LOOPBACK_CONSOLE) == 0) { 167219820Sjeff struct sockaddr_in sin; 168219820Sjeff int optval = 1; 169219820Sjeff 170219820Sjeff if ((p_oct->socket = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 171219820Sjeff OSM_LOG(p_log, OSM_LOG_ERROR, 172219820Sjeff "ERR 4B01: Failed to open console socket: %s\n", 173219820Sjeff strerror(errno)); 174219820Sjeff return -1; 175219820Sjeff } 176219820Sjeff setsockopt(p_oct->socket, SOL_SOCKET, SO_REUSEADDR, 177219820Sjeff &optval, sizeof(optval)); 178219820Sjeff sin.sin_family = AF_INET; 179219820Sjeff sin.sin_port = htons(opt->console_port); 180219820Sjeff if (strcmp(opt->console, OSM_REMOTE_CONSOLE) == 0) 181219820Sjeff sin.sin_addr.s_addr = htonl(INADDR_ANY); 182219820Sjeff else 183219820Sjeff sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 184219820Sjeff if (bind(p_oct->socket, &sin, sizeof(sin)) < 0) { 185219820Sjeff OSM_LOG(p_log, OSM_LOG_ERROR, 186219820Sjeff "ERR 4B02: Failed to bind console socket: %s\n", 187219820Sjeff strerror(errno)); 188219820Sjeff return -1; 189219820Sjeff } 190219820Sjeff if (listen(p_oct->socket, 1) < 0) { 191219820Sjeff OSM_LOG(p_log, OSM_LOG_ERROR, 192219820Sjeff "ERR 4B03: Failed to listen on socket: %s\n", 193219820Sjeff strerror(errno)); 194219820Sjeff return -1; 195219820Sjeff } 196219820Sjeff 197219820Sjeff signal(SIGPIPE, SIG_IGN); /* protect ourselves from closed pipes */ 198219820Sjeff p_oct->in = NULL; 199219820Sjeff p_oct->out = NULL; 200219820Sjeff p_oct->in_fd = -1; 201219820Sjeff p_oct->out_fd = -1; 202219820Sjeff OSM_LOG(p_log, OSM_LOG_INFO, 203219820Sjeff "Console listening on port %d\n", opt->console_port); 204219820Sjeff#endif 205219820Sjeff } 206219820Sjeff 207219820Sjeff return 0; 208219820Sjeff} 209219820Sjeff 210219820Sjeff/* clean up and release resources */ 211219820Sjeffvoid osm_console_exit(osm_console_t * p_oct, osm_log_t * p_log) 212219820Sjeff{ 213219820Sjeff // clean up and release resources, currently just close the socket 214219820Sjeff osm_console_close(p_oct, p_log); 215219820Sjeff} 216219820Sjeff 217219820Sjeff#ifdef ENABLE_OSM_CONSOLE_SOCKET 218219820Sjeffint cio_open(osm_console_t * p_oct, int new_fd, osm_log_t * p_log) 219219820Sjeff{ 220219820Sjeff // returns zero if opened fine, -1 otherwise 221219820Sjeff char *p_line; 222219820Sjeff size_t len; 223219820Sjeff ssize_t n; 224219820Sjeff 225219820Sjeff if (p_oct->in_fd >= 0) { 226219820Sjeff FILE *file = fdopen(new_fd, "w+"); 227219820Sjeff 228219820Sjeff fprintf(file, "OpenSM Console connection already in use\n" 229219820Sjeff " kill other session (y/n)? "); 230219820Sjeff fflush(file); 231219820Sjeff p_line = NULL; 232219820Sjeff n = getline(&p_line, &len, file); 233219820Sjeff if (n > 0 && (p_line[0] == 'y' || p_line[0] == 'Y')) { 234219820Sjeff osm_console_close(p_oct, p_log); 235219820Sjeff } else { 236219820Sjeff OSM_LOG(p_log, OSM_LOG_INFO, 237219820Sjeff "Console connection aborted: %s (%s)\n", 238219820Sjeff p_oct->client_hn, p_oct->client_ip); 239219820Sjeff close(new_fd); 240219820Sjeff return -1; 241219820Sjeff } 242219820Sjeff } 243219820Sjeff p_oct->in_fd = new_fd; 244219820Sjeff p_oct->out_fd = p_oct->in_fd; 245219820Sjeff p_oct->in = fdopen(p_oct->in_fd, "w+"); 246219820Sjeff p_oct->out = p_oct->in; 247219820Sjeff osm_console_prompt(p_oct->out); 248219820Sjeff OSM_LOG(p_log, OSM_LOG_INFO, 249219820Sjeff "Console connection accepted: %s (%s)\n", 250219820Sjeff p_oct->client_hn, p_oct->client_ip); 251219820Sjeff 252219820Sjeff return (p_oct->in == NULL) ? -1 : 0; 253219820Sjeff} 254219820Sjeff#endif 255