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