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                                   &section_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