]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/ofed/management/opensm/opensm/osm_console_io.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / ofed / management / opensm / opensm / osm_console_io.c
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
60 static 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
68 static 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
76 static 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
85 int 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
97 static 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 */
112 static 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
133 int 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
143 void osm_console_prompt(FILE * out)
144 {
145         if (out) {
146                 fprintf(out, "OpenSM %s", OSM_COMMAND_PROMPT);
147                 fflush(out);
148         }
149 }
150
151 int 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 */
211 void 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
218 int 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