1 /*****************************************************************************\
2 * $Id: ipmiconsole.c,v 1.102 2010-02-08 22:02:30 chu11 Exp $
3 *****************************************************************************
4 * Copyright (C) 2007-2015 Lawrence Livermore National Security, LLC.
5 * Copyright (C) 2006-2007 The Regents of the University of California.
6 * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
7 * Written by Albert Chu <chu11@llnl.gov>
8 * UCRL-CODE-221226
9 *
10 * This file is part of Ipmiconsole, a set of IPMI 2.0 SOL libraries
11 * and utilities. For details, see http://www.llnl.gov/linux/.
12 *
13 * Ipmiconsole is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by the
15 * Free Software Foundation; either version 3 of the License, or (at your
16 * option) any later version.
17 *
18 * Ipmiconsole is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
20 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 * for more details.
22 *
23 * You should have received a copy of the GNU General Public License along
24 * with Ipmiconsole. If not, see <http://www.gnu.org/licenses/>.
25 \*****************************************************************************/
26
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif /* HAVE_CONFIG_H */
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #if STDC_HEADERS
34 #include <string.h>
35 #endif /* STDC_HEADERS */
36 #if HAVE_UNISTD_H
37 #include <unistd.h>
38 #endif /* HAVE_UNISTD_H */
39 #if HAVE_FCNTL_H
40 #include <fcntl.h>
41 #endif /* HAVE_FCNTL_H */
42 #if TIME_WITH_SYS_TIME
43 #include <sys/time.h>
44 #include <time.h>
45 #else /* !TIME_WITH_SYS_TIME */
46 #if HAVE_SYS_TIME_H
47 #include <sys/time.h>
48 #else /* !HAVE_SYS_TIME_H */
49 #include <time.h>
50 #endif /* !HAVE_SYS_TIME_H */
51 #endif /* !TIME_WITH_SYS_TIME */
52 #include <sys/types.h>
53 #include <sys/select.h>
54 #ifdef HAVE_PTHREAD_H
55 #include <pthread.h>
56 #endif /* HAVE_PTHREAD_H */
57 #include <limits.h>
58 #include <sys/resource.h>
59 #include <assert.h>
60 #include <errno.h>
61
62 #include "ipmiconsole.h"
63 #include "ipmiconsole_defs.h"
64
65 #include "ipmiconsole_ctx.h"
66 #include "ipmiconsole_debug.h"
67 #include "ipmiconsole_engine.h"
68 #include "ipmiconsole_util.h"
69
70 #include "freeipmi-portability.h"
71 #include "conffile.h"
72 #include "fi_hostlist.h"
73 #include "network.h"
74 #include "parse-common.h"
75 #include "secure.h"
76
77 /*
78 * ipmi console errmsgs
79 */
80 static char *ipmiconsole_errmsgs[] =
81 {
82 "success", /* 0 */
83 "ctx null", /* 1 */
84 "ctt invalid", /* 2 */
85 "engine already setup", /* 3 */
86 "engine not setup", /* 4 */
87 "ctx not submitted", /* 5 */
88 "ctx is submitted", /* 6 */
89 "invalid parameters", /* 7 */
90 "hostname invalid", /* 8 */
91 "ipmi 2.0 unavailable", /* 9 */
92 "cipher suite id unavailable", /* 10 */
93 "username invalid", /* 11 */
94 "password invalid", /* 12 */
95 "k_g invalid", /* 13 */
96 "privilege level insufficient", /* 14 */
97 "privilege level cannot be obtained for this user", /* 15 */
98 "SOL unavailable", /* 16 */
99 "SOL in use", /* 17 */
100 "SOL session stolen", /* 18 */
101 "SOL requires encryption", /* 19 */
102 "SOL requires no encryption", /* 20 */
103 "BMC Busy", /* 21 */
104 "BMC Error", /* 22 */
105 "BMC Implementation", /* 23 */
106 "connection timeout", /* 24 */
107 "session timeout", /* 25 */
108 "excess retransmissions sent", /* 26 */
109 "excess errors received", /* 27 */
110 "out of memory", /* 28 */
111 "too many open files", /* 29 */
112 "internal system error", /* 30 */
113 "internal error", /* 31 */
114 "errnum out of range", /* 32 */
115 NULL
116 };
117
118 #define IPMICONSOLE_ENGINE_CLOSE_FD_STR "closefd"
119 #define IPMICONSOLE_ENGINE_OUTPUT_ON_SOL_ESTABLISHED_STR "outputonsolestablished"
120 #define IPMICONSOLE_ENGINE_LOCK_MEMORY_STR "lockmemory"
121 #define IPMICONSOLE_ENGINE_SERIAL_KEEPALIVE_STR "serialkeepalive"
122 #define IPMICONSOLE_ENGINE_SERIAL_KEEPALIVE_EMPTY_STR "serialkeepaliveempty"
123
124 #define IPMICONSOLE_BEHAVIOR_ERROR_ON_SOL_INUSE_STR "erroronsolinuse"
125 #define IPMICONSOLE_BEHAVIOR_DEACTIVATE_ONLY_STR "deactivateonly"
126 #define IPMICONSOLE_BEHAVIOR_DEACTIVATE_ALL_INSTANCES_STR "deactivateallinstances"
127
128 #define IPMICONSOLE_DEBUG_STDOUT_STR "stdout"
129 #define IPMICONSOLE_DEBUG_STDERR_STR "stderr"
130 #define IPMICONSOLE_DEBUG_SYSLOG_STR "syslog"
131 #define IPMICONSOLE_DEBUG_FILE_STR "file"
132 #define IPMICONSOLE_DEBUG_IPMI_PACKETS_STR "ipmipackets"
133
134 struct ipmiconsole_ctx_config default_config;
135
136 static int
_config_file_unsigned_int_positive(conffile_t cf,struct conffile_data * data,char * optionname,int option_type,void * option_ptr,int option_data,void * app_ptr,int app_data)137 _config_file_unsigned_int_positive (conffile_t cf,
138 struct conffile_data *data,
139 char *optionname,
140 int option_type,
141 void *option_ptr,
142 int option_data,
143 void *app_ptr,
144 int app_data)
145 {
146 unsigned int *value;
147
148 assert (data);
149 assert (option_ptr);
150
151 value = (unsigned int *)option_ptr;
152
153 if (data->intval <= 0)
154 {
155 IPMICONSOLE_DEBUG (("libipmiconsole config file %s invalid", optionname));
156 return (0);
157 }
158
159 *value = (unsigned int)data->intval;
160 return (0);
161 }
162
163 static int
_config_file_username(conffile_t cf,struct conffile_data * data,char * optionname,int option_type,void * option_ptr,int option_data,void * app_ptr,int app_data)164 _config_file_username (conffile_t cf,
165 struct conffile_data *data,
166 char *optionname,
167 int option_type,
168 void *option_ptr,
169 int option_data,
170 void *app_ptr,
171 int app_data)
172 {
173 assert (data);
174
175 if (strlen (data->string) > IPMI_MAX_USER_NAME_LENGTH)
176 {
177 IPMICONSOLE_DEBUG (("libipmiconsole config file username invalid length"));
178 return (0);
179 }
180
181 strcpy (default_config.username, data->string);
182
183 IPMICONSOLE_DEBUG (("libipmiconsole loaded alternate default username"));
184 return (0);
185 }
186
187 static int
_config_file_password(conffile_t cf,struct conffile_data * data,char * optionname,int option_type,void * option_ptr,int option_data,void * app_ptr,int app_data)188 _config_file_password (conffile_t cf,
189 struct conffile_data *data,
190 char *optionname,
191 int option_type,
192 void *option_ptr,
193 int option_data,
194 void *app_ptr,
195 int app_data)
196 {
197 assert (data);
198
199 if (strlen (data->string) > IPMI_2_0_MAX_PASSWORD_LENGTH)
200 {
201 IPMICONSOLE_DEBUG (("libipmiconsole config file password invalid length"));
202 return (0);
203 }
204
205 strcpy (default_config.password, data->string);
206
207 IPMICONSOLE_DEBUG (("libipmiconsole loaded alternate default password"));
208 return (0);
209 }
210
211 static int
_config_file_k_g(conffile_t cf,struct conffile_data * data,char * optionname,int option_type,void * option_ptr,int option_data,void * app_ptr,int app_data)212 _config_file_k_g (conffile_t cf,
213 struct conffile_data *data,
214 char *optionname,
215 int option_type,
216 void *option_ptr,
217 int option_data,
218 void *app_ptr,
219 int app_data)
220 {
221 int rv;
222
223 assert (data);
224
225 if ((rv = parse_kg (default_config.k_g, IPMI_MAX_K_G_LENGTH, data->string)) < 0)
226 {
227 IPMICONSOLE_DEBUG (("libipmiconsole config file k_g invalid format"));
228 return (0);
229 }
230
231 if (rv > 0)
232 default_config.k_g_len = rv;
233
234 IPMICONSOLE_DEBUG (("libipmiconsole loaded alternate default k_g"));
235 return (0);
236 }
237
238 static int
_config_file_privilege_level(conffile_t cf,struct conffile_data * data,char * optionname,int option_type,void * option_ptr,int option_data,void * app_ptr,int app_data)239 _config_file_privilege_level (conffile_t cf,
240 struct conffile_data *data,
241 char *optionname,
242 int option_type,
243 void *option_ptr,
244 int option_data,
245 void *app_ptr,
246 int app_data)
247 {
248 int tmp;
249
250 assert (data);
251
252 if ((tmp = parse_privilege_level (data->string)) < 0)
253 {
254 IPMICONSOLE_DEBUG (("libipmiconsole config file privilege level invalid"));
255 return (0);
256 }
257
258 default_config.privilege_level = tmp;
259
260 IPMICONSOLE_DEBUG (("libipmiconsole loaded alternate default privilege level"));
261 return (0);
262 }
263
264 static int
_config_file_cipher_suite_id(conffile_t cf,struct conffile_data * data,char * optionname,int option_type,void * option_ptr,int option_data,void * app_ptr,int app_data)265 _config_file_cipher_suite_id (conffile_t cf,
266 struct conffile_data *data,
267 char *optionname,
268 int option_type,
269 void *option_ptr,
270 int option_data,
271 void *app_ptr,
272 int app_data)
273 {
274 assert (data);
275
276 if (data->intval < IPMI_CIPHER_SUITE_ID_MIN
277 || data->intval > IPMI_CIPHER_SUITE_ID_MAX
278 || !IPMI_CIPHER_SUITE_ID_SUPPORTED (data->intval))
279 {
280 IPMICONSOLE_DEBUG (("libipmiconsole config file cipher suite id invalid"));
281 return (0);
282 }
283
284 default_config.cipher_suite_id = data->intval;
285
286 IPMICONSOLE_DEBUG (("libipmiconsole loaded alternate default cipher suite id"));
287 return (0);
288 }
289
290
291 static int
_config_file_workaround_flags(conffile_t cf,struct conffile_data * data,char * optionname,int option_type,void * option_ptr,int option_data,void * app_ptr,int app_data)292 _config_file_workaround_flags (conffile_t cf,
293 struct conffile_data *data,
294 char *optionname,
295 int option_type,
296 void *option_ptr,
297 int option_data,
298 void *app_ptr,
299 int app_data)
300 {
301 unsigned int workaround_flags = 0;
302 unsigned int i;
303
304 assert (data);
305
306 for (i = 0; i < data->stringlist_len; i++)
307 {
308 unsigned int outofband_2_0_flags, section_flags;
309
310 if (parse_workaround_flags (data->stringlist[i],
311 NULL,
312 &outofband_2_0_flags,
313 NULL,
314 NULL,
315 §ion_flags) < 0)
316 {
317 IPMICONSOLE_DEBUG (("libipmiconsole config file workaround flag invalid"));
318 return (0);
319 }
320
321 if (outofband_2_0_flags)
322 {
323 if (outofband_2_0_flags & IPMI_PARSE_WORKAROUND_FLAGS_OUTOFBAND_2_0_AUTHENTICATION_CAPABILITIES)
324 workaround_flags |= IPMICONSOLE_WORKAROUND_AUTHENTICATION_CAPABILITIES;
325 if (outofband_2_0_flags & IPMI_PARSE_WORKAROUND_FLAGS_OUTOFBAND_2_0_INTEL_2_0_SESSION)
326 workaround_flags |= IPMICONSOLE_WORKAROUND_INTEL_2_0_SESSION;
327 if (outofband_2_0_flags & IPMI_PARSE_WORKAROUND_FLAGS_OUTOFBAND_2_0_SUPERMICRO_2_0_SESSION)
328 workaround_flags |= IPMICONSOLE_WORKAROUND_SUPERMICRO_2_0_SESSION;
329 if (outofband_2_0_flags & IPMI_PARSE_WORKAROUND_FLAGS_OUTOFBAND_2_0_SUN_2_0_SESSION)
330 workaround_flags |= IPMICONSOLE_WORKAROUND_SUN_2_0_SESSION;
331 if (outofband_2_0_flags & IPMI_PARSE_WORKAROUND_FLAGS_OUTOFBAND_2_0_OPEN_SESSION_PRIVILEGE)
332 workaround_flags |= IPMICONSOLE_WORKAROUND_OPEN_SESSION_PRIVILEGE;
333 if (outofband_2_0_flags & IPMI_PARSE_WORKAROUND_FLAGS_OUTOFBAND_2_0_NON_EMPTY_INTEGRITY_CHECK_VALUE)
334 workaround_flags |= IPMICONSOLE_WORKAROUND_NON_EMPTY_INTEGRITY_CHECK_VALUE;
335 if (outofband_2_0_flags & IPMI_PARSE_WORKAROUND_FLAGS_OUTOFBAND_2_0_NO_CHECKSUM_CHECK)
336 workaround_flags |= IPMICONSOLE_WORKAROUND_NO_CHECKSUM_CHECK;
337 }
338
339 if (section_flags)
340 {
341 if (section_flags & IPMI_PARSE_SECTION_SPECIFIC_WORKAROUND_FLAGS_IGNORE_SOL_PAYLOAD_SIZE)
342 workaround_flags |= IPMICONSOLE_WORKAROUND_IGNORE_SOL_PAYLOAD_SIZE;
343 if (section_flags & IPMI_PARSE_SECTION_SPECIFIC_WORKAROUND_FLAGS_IGNORE_SOL_PORT)
344 workaround_flags |= IPMICONSOLE_WORKAROUND_IGNORE_SOL_PORT;
345 if (section_flags & IPMI_PARSE_SECTION_SPECIFIC_WORKAROUND_FLAGS_SKIP_SOL_ACTIVATION_STATUS)
346 workaround_flags |= IPMICONSOLE_WORKAROUND_SKIP_SOL_ACTIVATION_STATUS;
347 if (section_flags & IPMI_PARSE_SECTION_SPECIFIC_WORKAROUND_FLAGS_SKIP_CHANNEL_PAYLOAD_SUPPORT)
348 workaround_flags |= IPMICONSOLE_WORKAROUND_SKIP_CHANNEL_PAYLOAD_SUPPORT;
349 }
350 }
351
352 default_config.workaround_flags = workaround_flags;
353
354 IPMICONSOLE_DEBUG (("libipmiconsole loaded alternate default workaround flag"));
355 return (0);
356 }
357
358 static int
_config_file_engine_flags(conffile_t cf,struct conffile_data * data,char * optionname,int option_type,void * option_ptr,int option_data,void * app_ptr,int app_data)359 _config_file_engine_flags (conffile_t cf,
360 struct conffile_data *data,
361 char *optionname,
362 int option_type,
363 void *option_ptr,
364 int option_data,
365 void *app_ptr,
366 int app_data)
367 {
368 unsigned int engine_flags = 0;
369 unsigned int i;
370
371 assert (data);
372
373 for (i = 0; i < data->stringlist_len; i++)
374 {
375 if (!strcasecmp (data->stringlist[i], IPMICONSOLE_ENGINE_CLOSE_FD_STR))
376 engine_flags |= IPMICONSOLE_ENGINE_CLOSE_FD;
377 else if (!strcasecmp (data->stringlist[i], IPMICONSOLE_ENGINE_OUTPUT_ON_SOL_ESTABLISHED_STR))
378 engine_flags |= IPMICONSOLE_ENGINE_OUTPUT_ON_SOL_ESTABLISHED;
379 else if (!strcasecmp (data->stringlist[i], IPMICONSOLE_ENGINE_LOCK_MEMORY_STR))
380 engine_flags |= IPMICONSOLE_ENGINE_LOCK_MEMORY;
381 else if (!strcasecmp (data->stringlist[i], IPMICONSOLE_ENGINE_SERIAL_KEEPALIVE_STR))
382 engine_flags |= IPMICONSOLE_ENGINE_SERIAL_KEEPALIVE;
383 else if (!strcasecmp (data->stringlist[i], IPMICONSOLE_ENGINE_SERIAL_KEEPALIVE_EMPTY_STR))
384 engine_flags |= IPMICONSOLE_ENGINE_SERIAL_KEEPALIVE_EMPTY;
385 else
386 IPMICONSOLE_DEBUG (("libipmiconsole config file engine flag invalid"));
387 }
388
389 default_config.engine_flags = engine_flags;
390
391 IPMICONSOLE_DEBUG (("libipmiconsole loaded alternate default engine flag"));
392 return (0);
393 }
394
395 static int
_config_file_behavior_flags(conffile_t cf,struct conffile_data * data,char * optionname,int option_type,void * option_ptr,int option_data,void * app_ptr,int app_data)396 _config_file_behavior_flags (conffile_t cf,
397 struct conffile_data *data,
398 char *optionname,
399 int option_type,
400 void *option_ptr,
401 int option_data,
402 void *app_ptr,
403 int app_data)
404 {
405 unsigned int behavior_flags = 0;
406 unsigned int i;
407
408 assert (data);
409
410 for (i = 0; i < data->stringlist_len; i++)
411 {
412 if (!strcasecmp (data->stringlist[i], IPMICONSOLE_BEHAVIOR_ERROR_ON_SOL_INUSE_STR))
413 behavior_flags |= IPMICONSOLE_BEHAVIOR_ERROR_ON_SOL_INUSE;
414 else if (!strcasecmp (data->stringlist[i], IPMICONSOLE_BEHAVIOR_DEACTIVATE_ONLY_STR))
415 behavior_flags |= IPMICONSOLE_BEHAVIOR_DEACTIVATE_ONLY;
416 else if (!strcasecmp (data->stringlist[i], IPMICONSOLE_BEHAVIOR_DEACTIVATE_ALL_INSTANCES_STR))
417 behavior_flags |= IPMICONSOLE_BEHAVIOR_DEACTIVATE_ALL_INSTANCES;
418 else
419 IPMICONSOLE_DEBUG (("libipmiconsole config file behavior flag invalid"));
420 }
421
422 default_config.behavior_flags = behavior_flags;
423
424 IPMICONSOLE_DEBUG (("libipmiconsole loaded alternate default behavior flag"));
425 return (0);
426 }
427
428 static int
_config_file_debug_flags(conffile_t cf,struct conffile_data * data,char * optionname,int option_type,void * option_ptr,int option_data,void * app_ptr,int app_data)429 _config_file_debug_flags (conffile_t cf,
430 struct conffile_data *data,
431 char *optionname,
432 int option_type,
433 void *option_ptr,
434 int option_data,
435 void *app_ptr,
436 int app_data)
437 {
438 unsigned int debug_flags = 0;
439 unsigned int i;
440
441 assert (data);
442
443 for (i = 0; i < data->stringlist_len; i++)
444 {
445 if (!strcasecmp (data->stringlist[i], IPMICONSOLE_DEBUG_STDOUT_STR))
446 debug_flags |= IPMICONSOLE_DEBUG_STDOUT;
447 else if (!strcasecmp (data->stringlist[i], IPMICONSOLE_DEBUG_STDERR_STR))
448 debug_flags |= IPMICONSOLE_DEBUG_STDERR;
449 else if (!strcasecmp (data->stringlist[i], IPMICONSOLE_DEBUG_SYSLOG_STR))
450 debug_flags |= IPMICONSOLE_DEBUG_SYSLOG;
451 else if (!strcasecmp (data->stringlist[i], IPMICONSOLE_DEBUG_FILE_STR))
452 debug_flags |= IPMICONSOLE_DEBUG_FILE;
453 else if (!strcasecmp (data->stringlist[i], IPMICONSOLE_DEBUG_IPMI_PACKETS_STR))
454 debug_flags |= IPMICONSOLE_DEBUG_IPMI_PACKETS;
455 else
456 IPMICONSOLE_DEBUG (("libipmiconsole config file debug flag invalid"));
457 }
458
459 default_config.debug_flags = debug_flags;
460
461 IPMICONSOLE_DEBUG (("libipmiconsole loaded alternate default debug flag"));
462 return (0);
463 }
464
465 static int
_config_file_sol_payload_instance(conffile_t cf,struct conffile_data * data,char * optionname,int option_type,void * option_ptr,int option_data,void * app_ptr,int app_data)466 _config_file_sol_payload_instance (conffile_t cf,
467 struct conffile_data *data,
468 char *optionname,
469 int option_type,
470 void *option_ptr,
471 int option_data,
472 void *app_ptr,
473 int app_data)
474 {
475 unsigned int *value;
476
477 assert (data);
478 assert (option_ptr);
479
480 value = (unsigned int *)option_ptr;
481
482 if (data->intval <= 0
483 || !IPMI_PAYLOAD_INSTANCE_VALID (data->intval))
484 {
485 IPMICONSOLE_DEBUG (("libipmiconsole config file %s invalid", optionname));
486 return (0);
487 }
488
489 *value = (unsigned int)data->intval;
490 return (0);
491 }
492
493 static int
_ipmiconsole_defaults_setup(void)494 _ipmiconsole_defaults_setup (void)
495 {
496 int libipmiconsole_context_username_count = 0, libipmiconsole_context_password_count = 0,
497 libipmiconsole_context_k_g_count = 0, libipmiconsole_context_privilege_level_count = 0,
498 libipmiconsole_context_cipher_suite_id_count = 0,
499 libipmiconsole_context_workaround_flags_count = 0,
500 libipmiconsole_context_session_timeout_len_count = 0,
501 libipmiconsole_context_retransmission_timeout_len_count = 0,
502 libipmiconsole_context_retransmission_backoff_count_count = 0,
503 libipmiconsole_context_keepalive_timeout_len_count = 0,
504 libipmiconsole_context_retransmission_keepalive_timeout_len_count = 0,
505 libipmiconsole_context_acceptable_packet_errors_count_count = 0,
506 libipmiconsole_context_maximum_retransmission_count_count = 0,
507 libipmiconsole_context_engine_flags_count = 0,
508 libipmiconsole_context_behavior_flags_count = 0,
509 libipmiconsole_context_debug_flags_count = 0,
510 libipmiconsole_context_sol_payload_instance_count = 0;
511
512 struct conffile_option libipmiconsole_options[] =
513 {
514 {
515 "libipmiconsole-context-username",
516 CONFFILE_OPTION_STRING,
517 -1,
518 _config_file_username,
519 1,
520 0,
521 &libipmiconsole_context_username_count,
522 NULL,
523 0,
524 },
525 {
526 "libipmiconsole-context-password",
527 CONFFILE_OPTION_STRING,
528 -1,
529 _config_file_password,
530 1,
531 0,
532 &libipmiconsole_context_password_count,
533 NULL,
534 0,
535 },
536 {
537 "libipmiconsole-context-k_g",
538 CONFFILE_OPTION_STRING,
539 -1,
540 _config_file_k_g,
541 1,
542 0,
543 &libipmiconsole_context_k_g_count,
544 NULL,
545 0,
546 },
547 {
548 "libipmiconsole-context-privilege-level",
549 CONFFILE_OPTION_STRING,
550 -1,
551 _config_file_privilege_level,
552 1,
553 0,
554 &libipmiconsole_context_privilege_level_count,
555 NULL,
556 0,
557 },
558 {
559 "libipmiconsole-context-cipher-suite-id",
560 CONFFILE_OPTION_INT,
561 -1,
562 _config_file_cipher_suite_id,
563 1,
564 0,
565 &libipmiconsole_context_cipher_suite_id_count,
566 NULL,
567 0,
568 },
569 {
570 "libipmiconsole-context-workaround-flags",
571 CONFFILE_OPTION_LIST_STRING,
572 -1,
573 _config_file_workaround_flags,
574 1,
575 0,
576 &libipmiconsole_context_workaround_flags_count,
577 NULL,
578 0,
579 },
580 {
581 "libipmiconsole-context-session-timeout-len",
582 CONFFILE_OPTION_INT,
583 -1,
584 _config_file_unsigned_int_positive,
585 1,
586 0,
587 &libipmiconsole_context_session_timeout_len_count,
588 &(default_config.session_timeout_len),
589 0
590 },
591 {
592 "libipmiconsole-context-retransmission-timeout-len",
593 CONFFILE_OPTION_INT,
594 -1,
595 _config_file_unsigned_int_positive,
596 1,
597 0,
598 &libipmiconsole_context_retransmission_timeout_len_count,
599 &(default_config.retransmission_timeout_len),
600 0
601 },
602 {
603 "libipmiconsole-context-retransmission-backoff-count",
604 CONFFILE_OPTION_INT,
605 -1,
606 _config_file_unsigned_int_positive,
607 1,
608 0,
609 &libipmiconsole_context_retransmission_backoff_count_count,
610 &(default_config.retransmission_backoff_count),
611 0
612 },
613 {
614 "libipmiconsole-context-keepalive-timeout-len",
615 CONFFILE_OPTION_INT,
616 -1,
617 _config_file_unsigned_int_positive,
618 1,
619 0,
620 &libipmiconsole_context_keepalive_timeout_len_count,
621 &(default_config.keepalive_timeout_len),
622 0
623 },
624 {
625 "libipmiconsole-context-retransmission-keepalive-timeout-len",
626 CONFFILE_OPTION_INT,
627 -1,
628 _config_file_unsigned_int_positive,
629 1,
630 0,
631 &libipmiconsole_context_retransmission_keepalive_timeout_len_count,
632 &(default_config.retransmission_keepalive_timeout_len),
633 0
634 },
635 {
636 "libipmiconsole-context-acceptable-packet-errors-count",
637 CONFFILE_OPTION_INT,
638 -1,
639 _config_file_unsigned_int_positive,
640 1,
641 0,
642 &libipmiconsole_context_acceptable_packet_errors_count_count,
643 &(default_config.acceptable_packet_errors_count),
644 0
645 },
646 {
647 "libipmiconsole-context-maximum-retransmission-count",
648 CONFFILE_OPTION_INT,
649 -1,
650 _config_file_unsigned_int_positive,
651 1,
652 0,
653 &libipmiconsole_context_maximum_retransmission_count_count,
654 &(default_config.maximum_retransmission_count),
655 0
656 },
657 {
658 "libipmiconsole-context-engine-flags",
659 CONFFILE_OPTION_LIST_STRING,
660 -1,
661 _config_file_engine_flags,
662 1,
663 0,
664 &libipmiconsole_context_engine_flags_count,
665 NULL,
666 0,
667 },
668 {
669 "libipmiconsole-context-behavior-flags",
670 CONFFILE_OPTION_LIST_STRING,
671 -1,
672 _config_file_behavior_flags,
673 1,
674 0,
675 &libipmiconsole_context_behavior_flags_count,
676 NULL,
677 0,
678 },
679 {
680 "libipmiconsole-context-debug-flags",
681 CONFFILE_OPTION_LIST_STRING,
682 -1,
683 _config_file_debug_flags,
684 1,
685 0,
686 &libipmiconsole_context_debug_flags_count,
687 NULL,
688 0,
689 },
690 {
691 "libipmiconsole-context-sol-payload-instance",
692 CONFFILE_OPTION_INT,
693 -1,
694 _config_file_sol_payload_instance,
695 1,
696 0,
697 &libipmiconsole_context_sol_payload_instance_count,
698 &(default_config.sol_payload_instance),
699 0
700 },
701 };
702
703 conffile_t cf = NULL;
704 int rv = -1;
705 int libipmiconsole_options_len;
706
707 memset (&default_config, '\0', sizeof (struct ipmiconsole_ctx_config));
708
709 /* set base defaults */
710
711 default_config.privilege_level = IPMI_PRIVILEGE_LEVEL_DEFAULT;
712 default_config.cipher_suite_id = IPMI_CIPHER_SUITE_ID_DEFAULT;
713 default_config.session_timeout_len = IPMICONSOLE_SESSION_TIMEOUT_LENGTH_DEFAULT;
714 default_config.retransmission_timeout_len = IPMICONSOLE_RETRANSMISSION_TIMEOUT_LENGTH_DEFAULT;
715 default_config.retransmission_backoff_count = IPMICONSOLE_RETRANSMISSION_BACKOFF_COUNT_DEFAULT;
716 default_config.keepalive_timeout_len = IPMICONSOLE_KEEPALIVE_TIMEOUT_LENGTH_DEFAULT;
717 default_config.retransmission_keepalive_timeout_len = IPMICONSOLE_RETRANSMISSION_KEEPALIVE_TIMEOUT_LENGTH_DEFAULT;
718 default_config.acceptable_packet_errors_count = IPMICONSOLE_ACCEPTABLE_PACKET_ERRORS_COUNT_DEFAULT;
719 default_config.maximum_retransmission_count = IPMICONSOLE_MAXIMUM_RETRANSMISSION_COUNT_DEFAULT;
720 default_config.sol_payload_instance = IPMI_PAYLOAD_INSTANCE_DEFAULT;
721
722 if (!(cf = conffile_handle_create ()))
723 {
724 IPMICONSOLE_DEBUG (("conffile_handle_create: %s", strerror (errno)));
725 return (-1);
726 }
727
728 libipmiconsole_options_len = sizeof (libipmiconsole_options) / sizeof (struct conffile_option);
729 if (conffile_parse (cf,
730 LIBIPMICONSOLE_CONFIG_FILE_DEFAULT,
731 libipmiconsole_options,
732 libipmiconsole_options_len,
733 NULL,
734 0,
735 0) < 0)
736 {
737 char buf[CONFFILE_MAX_ERRMSGLEN];
738
739 /* Its not an error if the default configuration file doesn't exist */
740 if (conffile_errnum (cf) == CONFFILE_ERR_EXIST)
741 goto out;
742
743 if (conffile_errmsg (cf, buf, CONFFILE_MAX_ERRMSGLEN) < 0)
744 {
745 IPMICONSOLE_DEBUG (("libipmiconsole loaded alternate default debug flag"));
746 goto cleanup;
747 }
748 }
749
750 out:
751 rv = 0;
752 cleanup:
753 conffile_handle_destroy (cf);
754 return (rv);
755 }
756
757 int
ipmiconsole_engine_init(unsigned int thread_count,unsigned int debug_flags)758 ipmiconsole_engine_init (unsigned int thread_count, unsigned int debug_flags)
759 {
760 struct rlimit rlim;
761 unsigned int i;
762
763 if (thread_count > IPMICONSOLE_THREAD_COUNT_MAX
764 || (debug_flags != IPMICONSOLE_DEBUG_DEFAULT
765 && debug_flags & ~IPMICONSOLE_DEBUG_MASK))
766 {
767 errno = EINVAL;
768 return (-1);
769 }
770
771 if (!thread_count)
772 thread_count = IPMICONSOLE_THREAD_COUNT_DEFAULT;
773
774 /* Note: Must be called first before anything else for debugging purposes */
775 if (ipmiconsole_debug_setup (debug_flags) < 0)
776 goto cleanup;
777
778 if (ipmiconsole_engine_is_setup ())
779 return (0);
780
781 if (ipmiconsole_engine_setup (thread_count) < 0)
782 goto cleanup;
783
784 for (i = 0; i < thread_count; i++)
785 {
786 if (ipmiconsole_engine_thread_create () < 0)
787 goto cleanup;
788 }
789
790 /* If the file descriptor increase fails, ignore it */
791
792 if (getrlimit (RLIMIT_NOFILE, &rlim) == 0)
793 {
794 rlim.rlim_cur = rlim.rlim_max;
795 setrlimit (RLIMIT_NOFILE, &rlim);
796 }
797
798 if (_ipmiconsole_defaults_setup () < 0)
799 goto cleanup;
800
801 return (0);
802
803 cleanup:
804 ipmiconsole_debug_cleanup ();
805 ipmiconsole_engine_cleanup (0);
806 return (-1);
807 }
808
809 int
ipmiconsole_engine_submit(ipmiconsole_ctx_t c,Ipmiconsole_callback callback,void * callback_arg)810 ipmiconsole_engine_submit (ipmiconsole_ctx_t c,
811 Ipmiconsole_callback callback,
812 void *callback_arg)
813 {
814 int perr;
815
816 if (!c
817 || c->magic != IPMICONSOLE_CTX_MAGIC
818 || c->api_magic != IPMICONSOLE_CTX_API_MAGIC)
819 return (-1);
820
821 if (!ipmiconsole_engine_is_setup ())
822 {
823 ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_NOT_SETUP);
824 return (-1);
825 }
826
827 if (c->session_submitted)
828 {
829 ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_CTX_IS_SUBMITTED);
830 return (-1);
831 }
832
833 /* Set to success, so we know if an IPMI error occurred later */
834 ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_SUCCESS);
835
836 if (ipmiconsole_ctx_non_blocking_setup (c,
837 callback,
838 callback_arg) < 0)
839 goto cleanup;
840
841 /* session setup required before connection setup, so
842 * connection knows if IPv4 or IPv6 used
843 */
844 if (ipmiconsole_ctx_session_setup (c) < 0)
845 goto cleanup;
846
847 if (ipmiconsole_ctx_connection_setup (c) < 0)
848 goto cleanup;
849
850 if (ipmiconsole_engine_submit_ctx (c) < 0)
851 goto cleanup;
852
853 if ((perr = pthread_mutex_lock (&(c->signal.status_mutex))) != 0)
854 {
855 IPMICONSOLE_DEBUG (("pthread_mutex_lock: %s", strerror (perr)));
856 ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
857 /* don't go to cleanup, b/c the engine will call
858 * ipmiconsole_ctx_connection_cleanup_session_not_submitted().
859 */
860 goto cleanup_ctx_fds_only;
861 }
862
863 /* Check for NOT_SUBMITTED, conceivably SOL_ERROR or SOL_ESTABLISHED
864 * could already be set
865 */
866 if (c->signal.status == IPMICONSOLE_CTX_STATUS_NOT_SUBMITTED)
867 c->signal.status = IPMICONSOLE_CTX_STATUS_SUBMITTED;
868
869 if ((perr = pthread_mutex_unlock (&(c->signal.status_mutex))) != 0)
870 {
871 IPMICONSOLE_DEBUG (("pthread_mutex_unlock: %s", strerror (perr)));
872 ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
873 /* don't go to cleanup, b/c the engine will call
874 * ipmiconsole_ctx_connection_cleanup_session_not_submitted().
875 */
876 goto cleanup_ctx_fds_only;
877 }
878
879 /* may have been set already */
880 c->session_submitted++;
881
882 if ((perr = pthread_mutex_lock (&(c->signal.mutex_ctx_state))) != 0)
883 IPMICONSOLE_DEBUG (("pthread_mutex_lock: %s", strerror (perr)));
884
885 c->signal.ctx_state = IPMICONSOLE_CTX_STATE_ENGINE_SUBMITTED;
886
887 if ((perr = pthread_mutex_unlock (&(c->signal.mutex_ctx_state))) != 0)
888 IPMICONSOLE_DEBUG (("pthread_mutex_unlock: %s", strerror (perr)));
889
890 ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_SUCCESS);
891 return (0);
892
893 cleanup:
894 ipmiconsole_ctx_connection_cleanup_session_not_submitted (c);
895 cleanup_ctx_fds_only:
896 /* fds are the API responsibility, even though we didn't create them */
897 ipmiconsole_ctx_fds_cleanup (c);
898 return (-1);
899 }
900
901 static int
_ipmiconsole_blocking_notification_cleanup(ipmiconsole_ctx_t c)902 _ipmiconsole_blocking_notification_cleanup (ipmiconsole_ctx_t c)
903 {
904 int perr;
905
906 assert (c);
907 assert (c->magic == IPMICONSOLE_CTX_MAGIC);
908 assert (c->api_magic == IPMICONSOLE_CTX_API_MAGIC);
909
910 if ((perr = pthread_mutex_lock (&(c->blocking.blocking_mutex))) != 0)
911 {
912 IPMICONSOLE_DEBUG (("pthread_mutex_lock: %s", strerror (perr)));
913 ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
914 return (-1);
915 }
916
917 if (c->blocking.blocking_submit_requested)
918 {
919 /* ignore potential error, cleanup path */
920 close (c->blocking.blocking_notification[0]);
921 /* ignore potential error, cleanup path */
922 close (c->blocking.blocking_notification[1]);
923 c->blocking.blocking_notification[0] = -1;
924 c->blocking.blocking_notification[1] = -1;
925 c->blocking.blocking_submit_requested = 0;
926 c->blocking.sol_session_established = 0;
927 }
928
929 if ((perr = pthread_mutex_unlock (&(c->blocking.blocking_mutex))) != 0)
930 {
931 IPMICONSOLE_DEBUG (("pthread_mutex_unlock: %s", strerror (perr)));
932 ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
933 return (-1);
934 }
935
936 return (0);
937 }
938
939 static int
_ipmiconsole_blocking_notification_setup(ipmiconsole_ctx_t c)940 _ipmiconsole_blocking_notification_setup (ipmiconsole_ctx_t c)
941 {
942 assert (c);
943 assert (c->magic == IPMICONSOLE_CTX_MAGIC);
944 assert (c->api_magic == IPMICONSOLE_CTX_API_MAGIC);
945
946 /* We're setting up, so no mutex locking needed at this point */
947
948 if (pipe (c->blocking.blocking_notification) < 0)
949 {
950 IPMICONSOLE_CTX_DEBUG (c, ("pipe: %s", strerror (errno)));
951 if (errno == EMFILE)
952 ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_TOO_MANY_OPEN_FILES);
953 else
954 ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_SYSTEM_ERROR);
955 goto cleanup;
956 }
957 c->blocking.blocking_submit_requested++;
958 c->blocking.sol_session_established = 0;
959
960 if (ipmiconsole_set_closeonexec (c, c->blocking.blocking_notification[0]) < 0)
961 {
962 IPMICONSOLE_DEBUG (("closeonexec error"));
963 goto cleanup;
964 }
965 if (ipmiconsole_set_closeonexec (c, c->blocking.blocking_notification[1]) < 0)
966 {
967 IPMICONSOLE_DEBUG (("closeonexec error"));
968 goto cleanup;
969 }
970
971 return (0);
972
973 cleanup:
974 _ipmiconsole_blocking_notification_cleanup (c);
975 return (-1);
976 }
977
978 static int
_ipmiconsole_block(ipmiconsole_ctx_t c)979 _ipmiconsole_block (ipmiconsole_ctx_t c)
980 {
981 fd_set rds;
982 int n;
983
984 assert (c);
985 assert (c->magic == IPMICONSOLE_CTX_MAGIC);
986 assert (c->api_magic == IPMICONSOLE_CTX_API_MAGIC);
987 assert (c->blocking.blocking_submit_requested);
988
989 FD_ZERO (&rds);
990 FD_SET (c->blocking.blocking_notification[0], &rds);
991
992 /* No mutex required here, just reading off the pipe, the pipe is
993 * all controled in API land
994 */
995
996 if ((n = select (c->blocking.blocking_notification[0] + 1, &rds, NULL, NULL, NULL)) < 0)
997 {
998 IPMICONSOLE_CTX_DEBUG (c, ("select: %s", strerror (errno)));
999 ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_SYSTEM_ERROR);
1000 goto cleanup;
1001 }
1002
1003 if (!n)
1004 {
1005 IPMICONSOLE_CTX_DEBUG (c, ("select returned 0"));
1006 ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
1007 goto cleanup;
1008 }
1009
1010 if (FD_ISSET (c->blocking.blocking_notification[0], &rds))
1011 {
1012 uint8_t tmpbyte;
1013 ssize_t len;
1014
1015 if ((len = read (c->blocking.blocking_notification[0], (void *)&tmpbyte, 1)) < 0)
1016 {
1017 IPMICONSOLE_CTX_DEBUG (c, ("read: %s", strerror (errno)));
1018 ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_SYSTEM_ERROR);
1019 goto cleanup;
1020 }
1021
1022 if (!len)
1023 {
1024 IPMICONSOLE_CTX_DEBUG (c, ("blocking_notification closed"));
1025 ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
1026 goto cleanup;
1027 }
1028
1029 if (tmpbyte == IPMICONSOLE_BLOCKING_NOTIFICATION_SOL_SESSION_ESTABLISHED)
1030 goto success;
1031 else if (tmpbyte == IPMICONSOLE_BLOCKING_NOTIFICATION_SOL_SESSION_ERROR)
1032 goto cleanup;
1033 else if (c->config.behavior_flags & IPMICONSOLE_BEHAVIOR_DEACTIVATE_ONLY
1034 && tmpbyte == IPMICONSOLE_BLOCKING_NOTIFICATION_SOL_SESSION_DEACTIVATED)
1035 goto success;
1036 else
1037 {
1038 IPMICONSOLE_CTX_DEBUG (c, ("blocking_notification returned invalid data: %u", tmpbyte));
1039 ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
1040 goto cleanup;
1041 }
1042 }
1043
1044 success:
1045 return (0);
1046
1047 cleanup:
1048 return (-1);
1049 }
1050
1051 int
ipmiconsole_engine_submit_block(ipmiconsole_ctx_t c)1052 ipmiconsole_engine_submit_block (ipmiconsole_ctx_t c)
1053 {
1054 int perr;
1055
1056 if (!c
1057 || c->magic != IPMICONSOLE_CTX_MAGIC
1058 || c->api_magic != IPMICONSOLE_CTX_API_MAGIC)
1059 return (-1);
1060
1061 if (!ipmiconsole_engine_is_setup ())
1062 {
1063 ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_NOT_SETUP);
1064 return (-1);
1065 }
1066
1067 if (c->session_submitted)
1068 {
1069 ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_CTX_IS_SUBMITTED);
1070 return (-1);
1071 }
1072
1073 /* Set to success, so we know if an IPMI error occurred later */
1074 ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_SUCCESS);
1075
1076 /* session setup required before connection setup, so
1077 * connection knows if IPv4 or IPv6 used
1078 */
1079 if (ipmiconsole_ctx_session_setup (c) < 0)
1080 goto cleanup;
1081
1082 if (ipmiconsole_ctx_connection_setup (c) < 0)
1083 goto cleanup;
1084
1085 if (_ipmiconsole_blocking_notification_setup (c) < 0)
1086 goto cleanup;
1087
1088 if (ipmiconsole_engine_submit_ctx (c) < 0)
1089 goto cleanup;
1090
1091 if (_ipmiconsole_block (c) < 0)
1092 {
1093 /* don't go to cleanup, b/c the engine will call
1094 * ipmiconsole_ctx_connection_cleanup_session_not_submitted().
1095 */
1096 goto cleanup_ctx_fds_only;
1097 }
1098
1099 if ((perr = pthread_mutex_lock (&(c->signal.status_mutex))) != 0)
1100 {
1101 IPMICONSOLE_DEBUG (("pthread_mutex_lock: %s", strerror (perr)));
1102 ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
1103 /* don't go to cleanup, b/c the engine will call
1104 * ipmiconsole_ctx_connection_cleanup_session_not_submitted().
1105 */
1106 goto cleanup_ctx_fds_only;
1107 }
1108
1109 /* Check for NOT_SUBMITTED, conceivably SOL_ERROR or SOL_ESTABLISHED
1110 * could already be set
1111 */
1112 if (c->signal.status == IPMICONSOLE_CTX_STATUS_NOT_SUBMITTED)
1113 c->signal.status = IPMICONSOLE_CTX_STATUS_SUBMITTED;
1114
1115 if ((perr = pthread_mutex_unlock (&(c->signal.status_mutex))) != 0)
1116 {
1117 IPMICONSOLE_DEBUG (("pthread_mutex_unlock: %s", strerror (perr)));
1118 ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
1119 /* don't go to cleanup, b/c the engine will call
1120 * ipmiconsole_ctx_connection_cleanup_session_not_submitted().
1121 */
1122 goto cleanup_ctx_fds_only;
1123 }
1124
1125 _ipmiconsole_blocking_notification_cleanup (c);
1126
1127 /* may have been set already */
1128 c->session_submitted++;
1129
1130 if ((perr = pthread_mutex_lock (&(c->signal.mutex_ctx_state))) != 0)
1131 IPMICONSOLE_DEBUG (("pthread_mutex_lock: %s", strerror (perr)));
1132
1133 c->signal.ctx_state = IPMICONSOLE_CTX_STATE_ENGINE_SUBMITTED;
1134
1135 if ((perr = pthread_mutex_unlock (&(c->signal.mutex_ctx_state))) != 0)
1136 IPMICONSOLE_DEBUG (("pthread_mutex_unlock: %s", strerror (perr)));
1137
1138 ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_SUCCESS);
1139 return (0);
1140
1141 cleanup:
1142 ipmiconsole_ctx_connection_cleanup_session_not_submitted (c);
1143 cleanup_ctx_fds_only:
1144 _ipmiconsole_blocking_notification_cleanup (c);
1145 /* fds are the API responsibility, even though we didn't create them */
1146 ipmiconsole_ctx_fds_cleanup (c);
1147 return (-1);
1148 }
1149
1150 void
ipmiconsole_engine_teardown(int cleanup_sol_sessions)1151 ipmiconsole_engine_teardown (int cleanup_sol_sessions)
1152 {
1153 ipmiconsole_debug_cleanup ();
1154 ipmiconsole_engine_cleanup (cleanup_sol_sessions);
1155 }
1156
1157 ipmiconsole_ctx_t
ipmiconsole_ctx_create(const char * hostname,struct ipmiconsole_ipmi_config * ipmi_config,struct ipmiconsole_protocol_config * protocol_config,struct ipmiconsole_engine_config * engine_config)1158 ipmiconsole_ctx_create (const char *hostname,
1159 struct ipmiconsole_ipmi_config *ipmi_config,
1160 struct ipmiconsole_protocol_config *protocol_config,
1161 struct ipmiconsole_engine_config *engine_config)
1162 {
1163 ipmiconsole_ctx_t c = NULL;
1164 char *hostname_copy = NULL;
1165 char *port_copy = NULL;
1166 const char *hostname_ptr = NULL;
1167 const char *port_ptr = NULL;
1168 uint16_t port = RMCP_PRIMARY_RMCP_PORT;
1169 int ret;
1170
1171 if (!hostname
1172 || !ipmi_config
1173 || !protocol_config
1174 || !engine_config
1175 || (ipmi_config->username && strlen (ipmi_config->username) > IPMI_MAX_USER_NAME_LENGTH)
1176 || (ipmi_config->password && strlen (ipmi_config->password) > IPMI_2_0_MAX_PASSWORD_LENGTH)
1177 || (ipmi_config->k_g && ipmi_config->k_g_len > IPMI_MAX_K_G_LENGTH)
1178 || (ipmi_config->privilege_level >= 0
1179 && (ipmi_config->privilege_level != IPMICONSOLE_PRIVILEGE_USER
1180 && ipmi_config->privilege_level != IPMICONSOLE_PRIVILEGE_OPERATOR
1181 && ipmi_config->privilege_level != IPMICONSOLE_PRIVILEGE_ADMIN))
1182 || (ipmi_config->cipher_suite_id >= IPMI_CIPHER_SUITE_ID_MIN
1183 && !IPMI_CIPHER_SUITE_ID_SUPPORTED (ipmi_config->cipher_suite_id))
1184 || (ipmi_config->workaround_flags != IPMICONSOLE_WORKAROUND_DEFAULT
1185 && ipmi_config->workaround_flags & ~IPMICONSOLE_WORKAROUND_MASK)
1186 || (engine_config->engine_flags != IPMICONSOLE_ENGINE_DEFAULT
1187 && engine_config->engine_flags & ~IPMICONSOLE_ENGINE_MASK)
1188 || (engine_config->behavior_flags != IPMICONSOLE_BEHAVIOR_DEFAULT
1189 && engine_config->behavior_flags & ~IPMICONSOLE_BEHAVIOR_MASK)
1190 || (engine_config->debug_flags != IPMICONSOLE_DEBUG_DEFAULT
1191 && engine_config->debug_flags & ~IPMICONSOLE_DEBUG_MASK))
1192 {
1193 IPMICONSOLE_DEBUG (("invalid input parameters"));
1194 errno = EINVAL;
1195 return (NULL);
1196 }
1197
1198 /* Check for host:port or [Ipv6]:port format */
1199 if ((ret = host_is_host_with_port (hostname,
1200 &hostname_copy,
1201 &port_copy)) < 0)
1202 {
1203 IPMICONSOLE_DEBUG (("host_is_host_with_port: %s", errno));
1204 errno = EINVAL;
1205 return (NULL);
1206 }
1207
1208 if (ret)
1209 {
1210 hostname_ptr = hostname_copy;
1211 port_ptr = port_copy;
1212 }
1213 else
1214 hostname_ptr = hostname;
1215
1216 if ((ret = host_is_valid (hostname_ptr,
1217 port_ptr,
1218 &port)) < 0)
1219 {
1220 IPMICONSOLE_DEBUG (("host_is_valid: %s", errno));
1221 errno = EINVAL;
1222 goto free_cleanup;
1223 }
1224
1225 if (!ret)
1226 {
1227 IPMICONSOLE_DEBUG (("invalid input parameters"));
1228 errno = EINVAL;
1229 goto free_cleanup;
1230 }
1231
1232 /* If engine is not setup, the default_config is not yet known */
1233 if (!ipmiconsole_engine_is_setup ())
1234 {
1235 IPMICONSOLE_DEBUG (("engine not initialized"));
1236 errno = EAGAIN;
1237 goto free_cleanup;
1238 }
1239
1240 if ((engine_config->engine_flags != IPMICONSOLE_ENGINE_DEFAULT
1241 && engine_config->engine_flags & IPMICONSOLE_ENGINE_LOCK_MEMORY)
1242 || default_config.engine_flags & IPMICONSOLE_ENGINE_LOCK_MEMORY)
1243 {
1244 if (!(c = (ipmiconsole_ctx_t)secure_malloc (sizeof (struct ipmiconsole_ctx))))
1245 {
1246 errno = ENOMEM;
1247 goto free_cleanup;
1248 }
1249 }
1250 else
1251 {
1252 if (!(c = (ipmiconsole_ctx_t)malloc (sizeof (struct ipmiconsole_ctx))))
1253 {
1254 errno = ENOMEM;
1255 goto free_cleanup;
1256 }
1257 }
1258
1259 /* XXX: Should move much of this to engine_submit, to make context
1260 * creation faster for console concentrators
1261 */
1262
1263 if (ipmiconsole_ctx_setup (c) < 0)
1264 goto cleanup;
1265
1266 if (ipmiconsole_ctx_config_setup (c,
1267 hostname_ptr,
1268 port,
1269 ipmi_config,
1270 protocol_config,
1271 engine_config) < 0)
1272 goto cleanup;
1273
1274 /* must be called after ipmiconsole_ctx_config_setup() */
1275 if (ipmiconsole_ctx_debug_setup (c) < 0)
1276 goto cleanup;
1277
1278 if (ipmiconsole_ctx_signal_setup (c) < 0)
1279 goto cleanup;
1280
1281 if (ipmiconsole_ctx_blocking_setup (c) < 0)
1282 goto cleanup;
1283
1284 /* only initializes value, no need to destroy/cleanup anything in here */
1285 ipmiconsole_ctx_fds_setup (c);
1286
1287 c->session_submitted = 0;
1288
1289 free (hostname_copy);
1290 free (port_copy);
1291
1292 ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_SUCCESS);
1293 return (c);
1294
1295 cleanup:
1296
1297 ipmiconsole_ctx_config_cleanup (c);
1298
1299 ipmiconsole_ctx_debug_cleanup (c);
1300
1301 ipmiconsole_ctx_signal_cleanup (c);
1302
1303 ipmiconsole_ctx_blocking_cleanup (c);
1304
1305 /* Note: use engine_config->engine_flags not c->config.engine_flags,
1306 * b/c we don't know where we failed earlier.
1307 */
1308 if ((engine_config->engine_flags != IPMICONSOLE_ENGINE_DEFAULT
1309 && engine_config->engine_flags & IPMICONSOLE_ENGINE_LOCK_MEMORY)
1310 || default_config.engine_flags & IPMICONSOLE_ENGINE_LOCK_MEMORY)
1311 secure_free (c, sizeof (struct ipmiconsole_ctx));
1312 else
1313 free (c);
1314
1315 free_cleanup:
1316
1317 free (hostname_copy);
1318 free (port_copy);
1319
1320 return (NULL);
1321 }
1322
1323 int
ipmiconsole_ctx_set_config(ipmiconsole_ctx_t c,ipmiconsole_ctx_config_option_t config_option,void * config_option_value)1324 ipmiconsole_ctx_set_config (ipmiconsole_ctx_t c,
1325 ipmiconsole_ctx_config_option_t config_option,
1326 void *config_option_value)
1327 {
1328 unsigned int *tmpptr;
1329
1330 if (!c
1331 || c->magic != IPMICONSOLE_CTX_MAGIC
1332 || c->api_magic != IPMICONSOLE_CTX_API_MAGIC)
1333 return (-1);
1334
1335 if ((config_option != IPMICONSOLE_CTX_CONFIG_OPTION_SOL_PAYLOAD_INSTANCE)
1336 || !config_option_value)
1337 {
1338 ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_PARAMETERS);
1339 return (-1);
1340 }
1341
1342 if (c->session_submitted)
1343 {
1344 ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_CTX_IS_SUBMITTED);
1345 return (-1);
1346 }
1347
1348 switch (config_option)
1349 {
1350 case IPMICONSOLE_CTX_CONFIG_OPTION_SOL_PAYLOAD_INSTANCE:
1351 tmpptr = (unsigned int *)config_option_value;
1352 if (!IPMI_PAYLOAD_INSTANCE_VALID((*tmpptr)))
1353 {
1354 ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_PARAMETERS);
1355 return (-1);
1356 }
1357 c->config.sol_payload_instance = *(tmpptr);
1358 break;
1359 default:
1360 ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
1361 return (-1);
1362 }
1363
1364 ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_SUCCESS);
1365 return (0);
1366 }
1367
1368 int
ipmiconsole_ctx_get_config(ipmiconsole_ctx_t c,ipmiconsole_ctx_config_option_t config_option,void * config_option_value)1369 ipmiconsole_ctx_get_config (ipmiconsole_ctx_t c,
1370 ipmiconsole_ctx_config_option_t config_option,
1371 void *config_option_value)
1372 {
1373 unsigned int *tmpptr;
1374
1375 if (!c
1376 || c->magic != IPMICONSOLE_CTX_MAGIC
1377 || c->api_magic != IPMICONSOLE_CTX_API_MAGIC)
1378 return (-1);
1379
1380 if ((config_option != IPMICONSOLE_CTX_CONFIG_OPTION_SOL_PAYLOAD_INSTANCE)
1381 || !config_option_value)
1382 {
1383 ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_PARAMETERS);
1384 return (-1);
1385 }
1386
1387 switch (config_option)
1388 {
1389 case IPMICONSOLE_CTX_CONFIG_OPTION_SOL_PAYLOAD_INSTANCE:
1390 tmpptr = (unsigned int *)config_option_value;
1391 (*tmpptr) = c->config.sol_payload_instance;
1392 break;
1393 default:
1394 ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
1395 return (-1);
1396 }
1397
1398 ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_SUCCESS);
1399 return (0);
1400 }
1401
1402 int
ipmiconsole_ctx_errnum(ipmiconsole_ctx_t c)1403 ipmiconsole_ctx_errnum (ipmiconsole_ctx_t c)
1404 {
1405 if (!c)
1406 return (IPMICONSOLE_ERR_CTX_NULL);
1407 else if (c->magic != IPMICONSOLE_CTX_MAGIC
1408 || c->api_magic != IPMICONSOLE_CTX_API_MAGIC)
1409 return (IPMICONSOLE_ERR_CTX_INVALID);
1410 else
1411 return (ipmiconsole_ctx_get_errnum (c));
1412 }
1413
1414 char *
ipmiconsole_ctx_strerror(int errnum)1415 ipmiconsole_ctx_strerror (int errnum)
1416 {
1417 if (errnum >= IPMICONSOLE_ERR_SUCCESS && errnum <= IPMICONSOLE_ERR_ERRNUMRANGE)
1418 return (ipmiconsole_errmsgs[errnum]);
1419 else
1420 return (ipmiconsole_errmsgs[IPMICONSOLE_ERR_ERRNUMRANGE]);
1421 }
1422
1423 char *
ipmiconsole_ctx_errormsg(ipmiconsole_ctx_t c)1424 ipmiconsole_ctx_errormsg (ipmiconsole_ctx_t c)
1425 {
1426 return (ipmiconsole_ctx_strerror (ipmiconsole_ctx_errnum (c)));
1427 }
1428
1429 ipmiconsole_ctx_status_t
ipmiconsole_ctx_status(ipmiconsole_ctx_t c)1430 ipmiconsole_ctx_status (ipmiconsole_ctx_t c)
1431 {
1432 int status;
1433 int perr;
1434
1435 if (!c
1436 || c->magic != IPMICONSOLE_CTX_MAGIC
1437 || c->api_magic != IPMICONSOLE_CTX_API_MAGIC)
1438 return (IPMICONSOLE_CTX_STATUS_ERROR);
1439
1440 /* Do not check if the context is submitted, b/c it may not be.
1441 *
1442 * Also, do not set errnum == success for this function, it could be
1443 * returning IPMICONSOLE_CTX_STATUS_ERROR.
1444 */
1445
1446 if ((perr = pthread_mutex_lock (&(c->signal.status_mutex))) != 0)
1447 {
1448 IPMICONSOLE_DEBUG (("pthread_mutex_lock: %s", strerror (perr)));
1449 ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
1450 return (IPMICONSOLE_CTX_STATUS_ERROR);
1451 }
1452
1453 status = c->signal.status;
1454
1455 if ((perr = pthread_mutex_unlock (&(c->signal.status_mutex))) != 0)
1456 {
1457 IPMICONSOLE_DEBUG (("pthread_mutex_unlock: %s", strerror (perr)));
1458 ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
1459 return (IPMICONSOLE_CTX_STATUS_ERROR);
1460 }
1461
1462 return (status);
1463 }
1464
1465 int
ipmiconsole_ctx_fd(ipmiconsole_ctx_t c)1466 ipmiconsole_ctx_fd (ipmiconsole_ctx_t c)
1467 {
1468 if (!c
1469 || c->magic != IPMICONSOLE_CTX_MAGIC
1470 || c->api_magic != IPMICONSOLE_CTX_API_MAGIC)
1471 return (-1);
1472
1473 if (!c->session_submitted)
1474 {
1475 ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_CTX_NOT_SUBMITTED);
1476 return (-1);
1477 }
1478
1479 ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_SUCCESS);
1480 c->fds.user_fd_retrieved++;
1481 return (c->fds.user_fd);
1482 }
1483
1484 int
ipmiconsole_ctx_generate_break(ipmiconsole_ctx_t c)1485 ipmiconsole_ctx_generate_break (ipmiconsole_ctx_t c)
1486 {
1487 uint8_t tmpbyte;
1488
1489 if (!c
1490 || c->magic != IPMICONSOLE_CTX_MAGIC
1491 || c->api_magic != IPMICONSOLE_CTX_API_MAGIC)
1492 return (-1);
1493
1494 if (!c->session_submitted)
1495 {
1496 ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_CTX_NOT_SUBMITTED);
1497 return (-1);
1498 }
1499
1500 tmpbyte = IPMICONSOLE_PIPE_GENERATE_BREAK_CODE;
1501 if (write (c->fds.asynccomm[1], &tmpbyte, 1) < 0)
1502 {
1503 ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_SYSTEM_ERROR);
1504 return (-1);
1505 }
1506
1507 ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_SUCCESS);
1508 return (0);
1509 }
1510
1511 void
ipmiconsole_ctx_destroy(ipmiconsole_ctx_t c)1512 ipmiconsole_ctx_destroy (ipmiconsole_ctx_t c)
1513 {
1514 if (!c
1515 || c->magic != IPMICONSOLE_CTX_MAGIC
1516 || c->api_magic != IPMICONSOLE_CTX_API_MAGIC)
1517 return;
1518
1519 if (c->session_submitted)
1520 {
1521 int perr;
1522
1523 /* achu: fds cleanup will not race with engine polling, b/c the
1524 * garbage collection will not complete until the flags set
1525 * below are set.
1526 */
1527 ipmiconsole_ctx_fds_cleanup (c);
1528
1529 if ((perr = pthread_mutex_lock (&(c->signal.mutex_ctx_state))) != 0)
1530 IPMICONSOLE_DEBUG (("pthread_mutex_lock: %s", strerror (perr)));
1531
1532 assert (c->signal.ctx_state == IPMICONSOLE_CTX_STATE_ENGINE_SUBMITTED
1533 || c->signal.ctx_state == IPMICONSOLE_CTX_STATE_GARBAGE_COLLECTION_WAIT
1534 || c->signal.ctx_state == IPMICONSOLE_CTX_STATE_ENGINE_DESTROYED);
1535
1536 /* Be careful, if the mutex is destroyed we shouldn't unlock it. */
1537
1538 if (c->signal.ctx_state == IPMICONSOLE_CTX_STATE_ENGINE_SUBMITTED)
1539 {
1540 c->signal.ctx_state = IPMICONSOLE_CTX_STATE_USER_DESTROYED;
1541
1542 /* must change magic in this mutex, to avoid racing
1543 * to destroy the context.
1544 */
1545 c->api_magic = ~IPMICONSOLE_CTX_API_MAGIC;
1546
1547 if ((perr = pthread_mutex_unlock (&(c->signal.mutex_ctx_state))) != 0)
1548 IPMICONSOLE_DEBUG (("pthread_mutex_unlock: %s", strerror (perr)));
1549 }
1550 else if (c->signal.ctx_state == IPMICONSOLE_CTX_STATE_GARBAGE_COLLECTION_WAIT)
1551 {
1552 c->signal.ctx_state = IPMICONSOLE_CTX_STATE_GARBAGE_COLLECTION_USER_DESTROYED;
1553
1554 /* must change magic in this mutex, to avoid racing
1555 * to destroy the context.
1556 */
1557 c->api_magic = ~IPMICONSOLE_CTX_API_MAGIC;
1558
1559 if ((perr = pthread_mutex_unlock (&(c->signal.mutex_ctx_state))) != 0)
1560 IPMICONSOLE_DEBUG (("pthread_mutex_unlock: %s", strerror (perr)));
1561 }
1562 else if (c->signal.ctx_state == IPMICONSOLE_CTX_STATE_ENGINE_DESTROYED)
1563 {
1564 /* Engine has torndown, clean this thing up */
1565 ipmiconsole_ctx_config_cleanup (c);
1566 ipmiconsole_ctx_debug_cleanup (c);
1567 ipmiconsole_ctx_signal_cleanup (c);
1568 ipmiconsole_ctx_blocking_cleanup (c);
1569 ipmiconsole_ctx_cleanup (c);
1570
1571 /* No unlocking, mutex is now destroyed */
1572 }
1573 else
1574 {
1575 /* State IPMICONSOLE_CTX_STATE_INIT shouldn't be possible if submitted */
1576 /* State IPMICONSOLE_CTX_STATE_GARBAGE_COLLECTION_USER_DESTROYED or
1577 * IPMICONSOLE_CTX_STATE_USER_DESTROYED shouldn't be possible,
1578 * api_magic != IPMICONSOLE_CTX_API_MAGIC and we shouldn't be
1579 * at this point.
1580 */
1581 IPMICONSOLE_DEBUG (("invalid ctx_state in ipmiconsole_ctx_destroy: %d", c->signal.ctx_state));
1582
1583 if ((perr = pthread_mutex_unlock (&(c->signal.mutex_ctx_state))) != 0)
1584 IPMICONSOLE_DEBUG (("pthread_mutex_unlock: %s", strerror (perr)));
1585 }
1586
1587 return;
1588 }
1589
1590 /* else session never submitted, so we have to cleanup */
1591 assert(c->signal.ctx_state == IPMICONSOLE_CTX_STATE_INIT);
1592
1593 c->api_magic = ~IPMICONSOLE_CTX_API_MAGIC;
1594 ipmiconsole_ctx_config_cleanup (c);
1595 ipmiconsole_ctx_debug_cleanup (c);
1596 ipmiconsole_ctx_signal_cleanup (c);
1597 ipmiconsole_ctx_blocking_cleanup (c);
1598 ipmiconsole_ctx_cleanup (c);
1599 }
1600
1601 int
ipmiconsole_username_is_valid(const char * username)1602 ipmiconsole_username_is_valid (const char *username)
1603 {
1604 if (!username)
1605 return (0);
1606
1607 if (strlen (username) > IPMI_MAX_USER_NAME_LENGTH)
1608 return (0);
1609
1610 return (1);
1611 }
1612
1613 int
ipmiconsole_password_is_valid(const char * password)1614 ipmiconsole_password_is_valid (const char *password)
1615 {
1616 if (!password)
1617 return (0);
1618
1619 if (strlen (password) > IPMI_2_0_MAX_PASSWORD_LENGTH)
1620 return (0);
1621
1622 return (1);
1623 }
1624
1625 int
ipmiconsole_k_g_is_valid(const unsigned char * k_g,unsigned int k_g_len)1626 ipmiconsole_k_g_is_valid (const unsigned char *k_g, unsigned int k_g_len)
1627 {
1628 if (!k_g)
1629 return (0);
1630
1631 if (k_g_len > IPMI_MAX_K_G_LENGTH)
1632 return (0);
1633
1634 return (1);
1635 }
1636
1637 int
ipmiconsole_privilege_level_is_valid(int privilege_level)1638 ipmiconsole_privilege_level_is_valid (int privilege_level)
1639 {
1640 if (privilege_level != IPMICONSOLE_PRIVILEGE_USER
1641 && privilege_level != IPMICONSOLE_PRIVILEGE_OPERATOR
1642 && privilege_level != IPMICONSOLE_PRIVILEGE_ADMIN)
1643 return (0);
1644
1645 return (1);
1646 }
1647
1648 int
ipmiconsole_cipher_suite_id_is_valid(int cipher_suite_id)1649 ipmiconsole_cipher_suite_id_is_valid (int cipher_suite_id)
1650 {
1651 if (!IPMI_CIPHER_SUITE_ID_SUPPORTED (cipher_suite_id))
1652 return (0);
1653
1654 return (1);
1655 }
1656
1657 int
ipmiconsole_workaround_flags_is_valid(unsigned int workaround_flags)1658 ipmiconsole_workaround_flags_is_valid (unsigned int workaround_flags)
1659 {
1660 if (workaround_flags & ~IPMICONSOLE_WORKAROUND_MASK)
1661 return (0);
1662
1663 return (1);
1664 }
1665