1 /*
2  * Copyright (C) 2003-2015 FreeIPMI Core Team
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  *
17  */
18 
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif /* HAVE_CONFIG_H */
22 
23 #include <stdio.h>
24 #include <stdlib.h>
25 #ifdef STDC_HEADERS
26 #include <string.h>
27 #endif /* STDC_HEADERS */
28 #include <sys/socket.h>
29 #include <netinet/in.h>
30 #if TIME_WITH_SYS_TIME
31 #include <sys/time.h>
32 #include <time.h>
33 #else /* !TIME_WITH_SYS_TIME */
34 #if HAVE_SYS_TIME_H
35 #include <sys/time.h>
36 #else /* !HAVE_SYS_TIME_H */
37 #include <time.h>
38 #endif /* !HAVE_SYS_TIME_H */
39 #endif  /* !TIME_WITH_SYS_TIME */
40 #include <sys/types.h>
41 #include <sys/poll.h>
42 #if HAVE_UNISTD_H
43 #include <unistd.h>
44 #endif /* HAVE_UNISTD_H */
45 #include <assert.h>
46 #include <errno.h>
47 
48 #include "freeipmi/api/ipmi-messaging-support-cmds-api.h"
49 #include "freeipmi/debug/ipmi-debug.h"
50 #include "freeipmi/fiid/fiid.h"
51 #include "freeipmi/interface/ipmi-interface.h"
52 #include "freeipmi/interface/ipmi-ipmb-interface.h"
53 #include "freeipmi/interface/ipmi-lan-interface.h"
54 #include "freeipmi/interface/ipmi-rmcpplus-interface.h"
55 #include "freeipmi/interface/rmcp-interface.h"
56 #include "freeipmi/spec/ipmi-authentication-type-spec.h"
57 #include "freeipmi/spec/ipmi-channel-spec.h"
58 #include "freeipmi/spec/ipmi-cmd-spec.h"
59 #include "freeipmi/spec/ipmi-comp-code-spec.h"
60 #include "freeipmi/spec/ipmi-ipmb-lun-spec.h"
61 #include "freeipmi/spec/ipmi-netfn-spec.h"
62 #include "freeipmi/spec/ipmi-privilege-level-spec.h"
63 #include "freeipmi/spec/ipmi-rmcpplus-status-spec.h"
64 #include "freeipmi/spec/ipmi-slave-address-spec.h"
65 #include "freeipmi/util/ipmi-cipher-suite-util.h"
66 #include "freeipmi/util/ipmi-lan-util.h"
67 #include "freeipmi/util/ipmi-outofband-util.h"
68 #include "freeipmi/util/ipmi-rmcpplus-util.h"
69 
70 #include "ipmi-api-defs.h"
71 #include "ipmi-api-trace.h"
72 #include "ipmi-api-util.h"
73 #include "ipmi-lan-session-common.h"
74 
75 #include "libcommon/ipmi-fiid-util.h"
76 
77 #include "freeipmi-portability.h"
78 #include "debug-util.h"
79 
80 #define IPMI_LAN_BACKOFF_COUNT         2
81 
82 struct socket_to_close {
83   int fd;
84   struct socket_to_close *next;
85 };
86 
87 #define IPMI_PKT_PAD 1024
88 
89 void
api_lan_cmd_get_session_parameters(ipmi_ctx_t ctx,uint8_t * authentication_type,unsigned int * internal_workaround_flags)90 api_lan_cmd_get_session_parameters (ipmi_ctx_t ctx,
91                                     uint8_t *authentication_type,
92                                     unsigned int *internal_workaround_flags)
93 {
94   assert (ctx
95           && ctx->magic == IPMI_CTX_MAGIC
96           && ctx->type == IPMI_DEVICE_LAN
97           && authentication_type
98           && internal_workaround_flags);
99 
100   (*authentication_type) = IPMI_AUTHENTICATION_TYPE_NONE;
101   (*internal_workaround_flags) = 0;
102 
103   if (ctx->io.outofband.per_msg_auth_disabled)
104     {
105       (*authentication_type) = IPMI_AUTHENTICATION_TYPE_NONE;
106       if (ctx->workaround_flags_outofband & IPMI_WORKAROUND_FLAGS_OUTOFBAND_CHECK_UNEXPECTED_AUTHCODE)
107         (*internal_workaround_flags) |= IPMI_INTERNAL_WORKAROUND_FLAGS_CHECK_UNEXPECTED_AUTHCODE;
108     }
109   else
110     (*authentication_type) = ctx->io.outofband.authentication_type;
111 }
112 
113 void
api_lan_2_0_cmd_get_session_parameters(ipmi_ctx_t ctx,uint8_t * payload_authenticated,uint8_t * payload_encrypted)114 api_lan_2_0_cmd_get_session_parameters (ipmi_ctx_t ctx,
115                                         uint8_t *payload_authenticated,
116                                         uint8_t *payload_encrypted)
117 {
118   assert (ctx
119           && ctx->magic == IPMI_CTX_MAGIC
120           && ctx->type == IPMI_DEVICE_LAN_2_0
121           && payload_authenticated
122           && payload_encrypted);
123 
124   if (ctx->io.outofband.integrity_algorithm == IPMI_INTEGRITY_ALGORITHM_NONE)
125     (*payload_authenticated) = IPMI_PAYLOAD_FLAG_UNAUTHENTICATED;
126   else
127     (*payload_authenticated) = IPMI_PAYLOAD_FLAG_AUTHENTICATED;
128 
129   if (ctx->io.outofband.confidentiality_algorithm == IPMI_CONFIDENTIALITY_ALGORITHM_NONE)
130     (*payload_encrypted) = IPMI_PAYLOAD_FLAG_UNENCRYPTED;
131   else
132     (*payload_encrypted) = IPMI_PAYLOAD_FLAG_ENCRYPTED;
133 }
134 
135 static int
_session_timed_out(ipmi_ctx_t ctx)136 _session_timed_out (ipmi_ctx_t ctx)
137 {
138   struct timeval current;
139   struct timeval session_timeout;
140   struct timeval session_timeout_len;
141 
142   assert (ctx
143           && ctx->magic == IPMI_CTX_MAGIC
144           && (ctx->type == IPMI_DEVICE_LAN
145               || ctx->type == IPMI_DEVICE_LAN_2_0));
146 
147   session_timeout_len.tv_sec = ctx->io.outofband.session_timeout / 1000;
148   session_timeout_len.tv_usec = (ctx->io.outofband.session_timeout - (session_timeout_len.tv_sec * 1000)) * 1000;
149   timeradd (&(ctx->io.outofband.last_received), &session_timeout_len, &session_timeout);
150 
151   if (gettimeofday (&current, NULL) < 0)
152     {
153       API_ERRNO_TO_API_ERRNUM (ctx, errno);
154       return (-1);
155     }
156 
157   return (timercmp (&current, &session_timeout, >));
158 }
159 
160 /* return 1 on continue, 0 if timeout already happened, -1 on error */
161 static int
_calculate_timeout(ipmi_ctx_t ctx,unsigned int retransmission_count,struct timeval * recv_starttime,struct timeval * timeout)162 _calculate_timeout (ipmi_ctx_t ctx,
163                     unsigned int retransmission_count,
164                     struct timeval *recv_starttime,
165                     struct timeval *timeout)
166 {
167   struct timeval current;
168   struct timeval session_timeout;
169   struct timeval session_timeout_len;
170   struct timeval session_timeout_val;
171   struct timeval retransmission_timeout;
172   struct timeval retransmission_timeout_len;
173   struct timeval retransmission_timeout_val;
174   struct timeval already_timedout_check;
175   unsigned int retransmission_timeout_multiplier;
176 
177   assert (ctx
178           && ctx->magic == IPMI_CTX_MAGIC
179           && (ctx->type == IPMI_DEVICE_LAN
180               || ctx->type == IPMI_DEVICE_LAN_2_0)
181           && recv_starttime
182           && timeout);
183 
184   if (gettimeofday (&current, NULL) < 0)
185     {
186       API_ERRNO_TO_API_ERRNUM (ctx, errno);
187       return (-1);
188     }
189 
190   session_timeout_len.tv_sec = ctx->io.outofband.session_timeout / 1000;
191   session_timeout_len.tv_usec = (ctx->io.outofband.session_timeout - (session_timeout_len.tv_sec * 1000)) * 1000;
192 
193   timeradd (recv_starttime, &session_timeout_len, &session_timeout);
194   timersub (&session_timeout, recv_starttime, &session_timeout_val);
195 
196   retransmission_timeout_multiplier = (retransmission_count / IPMI_LAN_BACKOFF_COUNT) + 1;
197 
198   retransmission_timeout_len.tv_sec = (retransmission_timeout_multiplier * ctx->io.outofband.retransmission_timeout) / 1000;
199   retransmission_timeout_len.tv_usec = ((retransmission_timeout_multiplier * ctx->io.outofband.retransmission_timeout) - (retransmission_timeout_len.tv_sec * 1000)) * 1000;
200 
201   timeradd (&ctx->io.outofband.last_send, &retransmission_timeout_len, &retransmission_timeout);
202   timersub (&retransmission_timeout, recv_starttime, &retransmission_timeout_val);
203 
204   if (timercmp (&retransmission_timeout_val, &session_timeout_val, <))
205     {
206       timeout->tv_sec = retransmission_timeout_val.tv_sec;
207       timeout->tv_usec = retransmission_timeout_val.tv_usec;
208     }
209   else
210     {
211       timeout->tv_sec = session_timeout_val.tv_sec;
212       timeout->tv_usec = session_timeout_val.tv_usec;
213     }
214 
215   /* See portability issue below regarding ECONNRESET and ECONNREFUSED
216    * to see why there could be two calls to this in a row, and thus
217    * this check is necessary
218    */
219 
220   timersub (&current, recv_starttime, &already_timedout_check);
221 
222   if (timercmp (timeout, &already_timedout_check, <))
223     return (0);
224 
225   return (1);
226 }
227 
228 static int
_api_lan_recvfrom(ipmi_ctx_t ctx,void * pkt,unsigned int pkt_len,unsigned int retransmission_count,struct timeval * recv_starttime)229 _api_lan_recvfrom (ipmi_ctx_t ctx,
230                    void *pkt,
231                    unsigned int pkt_len,
232                    unsigned int retransmission_count,
233                    struct timeval *recv_starttime)
234 {
235   int status = 0;
236   int recv_len;
237   int ret;
238 
239   assert (ctx
240           && ctx->magic == IPMI_CTX_MAGIC
241           && (ctx->type == IPMI_DEVICE_LAN
242               || ctx->type == IPMI_DEVICE_LAN_2_0)
243           && ctx->io.outofband.sockfd
244           && pkt
245           && pkt_len
246           && recv_starttime);
247 
248   if (ctx->io.outofband.retransmission_timeout)
249     {
250       struct timeval timeout;
251       struct pollfd pfd_read;
252       int timeoutms;
253 
254       if ((ret = _calculate_timeout (ctx,
255                                      retransmission_count,
256                                      recv_starttime,
257                                      &timeout)) < 0)
258         return (-1);
259 
260       if (!ret)
261         return (0);
262 
263       pfd_read.fd = ctx->io.outofband.sockfd;
264       pfd_read.events = POLLIN;
265       pfd_read.revents = 0;
266 
267       /* XXX: potential overflow scenarios? */
268       timeoutms = (timeout.tv_sec * 1000) + (timeout.tv_usec / 1000);
269 
270       if ((status = poll (&pfd_read, 1, timeoutms)) < 0)
271         {
272           API_ERRNO_TO_API_ERRNUM (ctx, errno);
273           return (-1);
274         }
275 
276       if (!status)
277         return (0); /* resend the request */
278     }
279 
280   do
281     {
282       /* For receive side, ipmi_lan_recvfrom and
283        * ipmi_rmcpplus_recvfrom are identical.  So we just use
284        * ipmi_lan_recvfrom for both.
285        *
286        * In event of future change, should use util functions
287        * ipmi_is_ipmi_1_5_packet or ipmi_is_ipmi_2_0_packet
288        * appropriately.
289        */
290       recv_len = ipmi_lan_recvfrom (ctx->io.outofband.sockfd,
291                                     pkt,
292                                     pkt_len,
293                                     0,
294                                     NULL,
295                                     NULL);
296     } while (recv_len < 0 && errno == EINTR);
297 
298   return (recv_len);
299 }
300 
301 static void
_api_lan_dump_rq(ipmi_ctx_t ctx,const void * pkt,unsigned int pkt_len,uint8_t cmd,uint8_t net_fn,uint8_t group_extension,fiid_obj_t obj_cmd_rq)302 _api_lan_dump_rq (ipmi_ctx_t ctx,
303                   const void *pkt,
304                   unsigned int pkt_len,
305                   uint8_t cmd,
306                   uint8_t net_fn,
307                   uint8_t group_extension,
308                   fiid_obj_t obj_cmd_rq)
309 {
310   fiid_field_t *tmpl_cmd = NULL;
311 
312   assert (ctx
313           && ctx->magic == IPMI_CTX_MAGIC
314           && (ctx->flags & IPMI_FLAGS_DEBUG_DUMP)
315           && pkt
316           && pkt_len
317           && fiid_obj_valid (obj_cmd_rq));
318 
319   /* Don't cleanup/return an error here.  It's just debug code. */
320 
321   if ((tmpl_cmd = fiid_obj_template (obj_cmd_rq)))
322     {
323       char hdrbuf[DEBUG_UTIL_HDR_BUFLEN];
324 
325       debug_hdr_cmd (DEBUG_UTIL_TYPE_IPMI_1_5,
326                      DEBUG_UTIL_DIRECTION_REQUEST,
327                      net_fn,
328                      cmd,
329                      group_extension,
330                      hdrbuf,
331                      DEBUG_UTIL_HDR_BUFLEN);
332 
333       if (ctx->tmpl_ipmb_cmd_rq)
334         ipmi_dump_lan_packet_ipmb (STDERR_FILENO,
335                                    ctx->io.outofband.hostname,
336                                    hdrbuf,
337                                    NULL,
338                                    pkt,
339                                    pkt_len,
340                                    tmpl_lan_msg_hdr_rq,
341                                    tmpl_cmd,
342                                    tmpl_ipmb_msg_hdr_rq,
343                                    ctx->tmpl_ipmb_cmd_rq);
344       else
345         ipmi_dump_lan_packet (STDERR_FILENO,
346                               ctx->io.outofband.hostname,
347                               hdrbuf,
348                               NULL,
349                               pkt,
350                               pkt_len,
351                               tmpl_lan_msg_hdr_rq,
352                               tmpl_cmd);
353 
354       fiid_template_free (tmpl_cmd);
355     }
356 }
357 
358 static void
_api_lan_dump_rs(ipmi_ctx_t ctx,const void * pkt,unsigned int pkt_len,uint8_t cmd,uint8_t net_fn,uint8_t group_extension,fiid_obj_t obj_cmd_rs)359 _api_lan_dump_rs (ipmi_ctx_t ctx,
360                   const void *pkt,
361                   unsigned int pkt_len,
362                   uint8_t cmd,
363                   uint8_t net_fn,
364                   uint8_t group_extension,
365                   fiid_obj_t obj_cmd_rs)
366 {
367   fiid_field_t *tmpl_cmd = NULL;
368 
369   assert (ctx
370           && ctx->magic == IPMI_CTX_MAGIC
371           && (ctx->flags & IPMI_FLAGS_DEBUG_DUMP)
372           && pkt
373           && pkt_len
374           && fiid_obj_valid (obj_cmd_rs));
375 
376   /* Don't cleanup/return an error here.  It's just debug code. */
377 
378   if ((tmpl_cmd = fiid_obj_template (obj_cmd_rs)))
379     {
380       char hdrbuf[DEBUG_UTIL_HDR_BUFLEN];
381 
382       debug_hdr_cmd (DEBUG_UTIL_TYPE_IPMI_1_5,
383                      DEBUG_UTIL_DIRECTION_RESPONSE,
384                      net_fn,
385                      cmd,
386                      group_extension,
387                      hdrbuf,
388                      DEBUG_UTIL_HDR_BUFLEN);
389 
390       ipmi_dump_lan_packet (STDERR_FILENO,
391                             ctx->io.outofband.hostname,
392                             hdrbuf,
393                             NULL,
394                             pkt,
395                             pkt_len,
396                             tmpl_lan_msg_hdr_rs,
397                             tmpl_cmd);
398 
399       fiid_template_free (tmpl_cmd);
400     }
401 }
402 
403 static int
_ipmi_check_session_sequence_number(ipmi_ctx_t ctx,uint32_t session_sequence_number)404 _ipmi_check_session_sequence_number (ipmi_ctx_t ctx,
405                                      uint32_t session_sequence_number)
406 {
407   int rv = 0;
408 
409   /* achu: This algorithm is more or less from Appendix A of the IPMI
410    * spec.  It may not be entirely necessary, since the requester
411    * sequence number puts packets into lock-step mode.  Oh well.
412    *
413    * I know that technically I could remove a lot of code here if I
414    * just let unsigned ints be unsigned ints (i.e. 0x00 - 0xff = 1).
415    * I dunno, I like to see all of the code actually written out b/c
416    * it makes more sense to the casual code reviewer.  Maybe I'll
417    * change it later.
418    */
419 
420   assert (ctx
421           && ctx->magic == IPMI_CTX_MAGIC
422           && (ctx->type == IPMI_DEVICE_LAN
423               || ctx->type == IPMI_DEVICE_LAN_2_0));
424 
425   /* IPMI Workaround (achu)
426    *
427    * Discovered on Sun Fire 4100.
428    *
429    * The session sequence numbers for IPMI 1.5 are the wrong endian.
430    * So we have to flip the bits to workaround it.
431    */
432   if (ctx->workaround_flags_outofband & IPMI_WORKAROUND_FLAGS_OUTOFBAND_BIG_ENDIAN_SEQUENCE_NUMBER)
433     {
434       uint32_t tmp_session_sequence_number = session_sequence_number;
435 
436       session_sequence_number =
437         ((tmp_session_sequence_number & 0xFF000000) >> 24)
438         | ((tmp_session_sequence_number & 0x00FF0000) >> 8)
439         | ((tmp_session_sequence_number & 0x0000FF00) << 8)
440         | ((tmp_session_sequence_number & 0x000000FF) << 24);
441     }
442 
443   if (ctx->type == IPMI_DEVICE_LAN)
444     {
445       if ((rv = ipmi_check_session_sequence_number_1_5 (session_sequence_number,
446                                                         &(ctx->io.outofband.highest_received_sequence_number),
447                                                         &(ctx->io.outofband.previously_received_list),
448                                                         0)) < 0)
449         {
450           {
451             API_ERRNO_TO_API_ERRNUM (ctx, errno);
452             goto cleanup;
453           }
454         }
455     }
456   else
457     {
458       if ((rv = ipmi_check_session_sequence_number_2_0 (session_sequence_number,
459                                                         &(ctx->io.outofband.highest_received_sequence_number),
460                                                         &(ctx->io.outofband.previously_received_list),
461                                                         0)) < 0)
462         {
463           {
464             API_ERRNO_TO_API_ERRNUM (ctx, errno);
465             goto cleanup;
466           }
467         }
468     }
469 
470  cleanup:
471   return (rv);
472 }
473 
474 static int
_api_lan_cmd_send(ipmi_ctx_t ctx,uint8_t lun,uint8_t net_fn,uint8_t authentication_type,uint32_t session_sequence_number,uint32_t session_id,uint8_t rq_seq,const char * password,unsigned int password_len,uint8_t cmd,uint8_t group_extension,fiid_obj_t obj_cmd_rq)475 _api_lan_cmd_send (ipmi_ctx_t ctx,
476                    uint8_t lun,
477                    uint8_t net_fn,
478                    uint8_t authentication_type,
479                    uint32_t session_sequence_number,
480                    uint32_t session_id,
481                    uint8_t rq_seq,
482                    const char *password,
483                    unsigned int password_len,
484                    uint8_t cmd, /* for debug dumping */
485                    uint8_t group_extension, /* for debug dumping */
486                    fiid_obj_t obj_cmd_rq)
487 {
488   uint8_t *pkt = NULL;
489   unsigned int pkt_len = 0;
490   int cmd_len = 0;
491   int send_len = 0;
492   int ret, rv = -1;
493 
494   assert (ctx
495           && ctx->magic == IPMI_CTX_MAGIC
496           && (ctx->type == IPMI_DEVICE_LAN
497               || ctx->type == IPMI_DEVICE_LAN_2_0)
498           && ctx->io.outofband.sockfd
499           && IPMI_BMC_LUN_VALID (lun)
500           && IPMI_NET_FN_VALID (net_fn)
501           && IPMI_1_5_AUTHENTICATION_TYPE_VALID (authentication_type)
502           && !(password && password_len > IPMI_1_5_MAX_PASSWORD_LENGTH)
503           && fiid_obj_valid (obj_cmd_rq)
504           && fiid_obj_packet_valid (obj_cmd_rq) == 1);
505 
506   if ((cmd_len = fiid_obj_len_bytes (obj_cmd_rq)) < 0)
507     {
508       API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_cmd_rq);
509       goto cleanup;
510     }
511 
512   /* variable based on authentication, etc. 1024 extra is enough */
513   pkt_len = cmd_len + IPMI_PKT_PAD;
514 
515   if (!(pkt = malloc (pkt_len)))
516     {
517       API_ERRNO_TO_API_ERRNUM (ctx, errno);
518       goto cleanup;
519     }
520 
521   if (fill_rmcp_hdr_ipmi (ctx->io.outofband.rq.obj_rmcp_hdr) < 0)
522     {
523       API_ERRNO_TO_API_ERRNUM (ctx, errno);
524       goto cleanup;
525     }
526 
527   if (fill_lan_msg_hdr (IPMI_SLAVE_ADDRESS_BMC,
528                         net_fn,
529                         lun,
530                         rq_seq,
531                         ctx->io.outofband.rq.obj_lan_msg_hdr) < 0)
532     {
533       API_ERRNO_TO_API_ERRNUM (ctx, errno);
534       goto cleanup;
535     }
536 
537   if (fill_lan_session_hdr (authentication_type,
538                             session_sequence_number,
539                             session_id,
540                             ctx->io.outofband.rq.obj_lan_session_hdr) < 0)
541     {
542       API_ERRNO_TO_API_ERRNUM (ctx, errno);
543       goto cleanup;
544     }
545 
546   if ((send_len = assemble_ipmi_lan_pkt (ctx->io.outofband.rq.obj_rmcp_hdr,
547                                          ctx->io.outofband.rq.obj_lan_session_hdr,
548                                          ctx->io.outofband.rq.obj_lan_msg_hdr,
549                                          obj_cmd_rq,
550                                          password,
551                                          password_len,
552                                          pkt,
553                                          pkt_len,
554                                          IPMI_INTERFACE_FLAGS_DEFAULT)) < 0)
555     {
556       API_ERRNO_TO_API_ERRNUM (ctx, errno);
557       goto cleanup;
558     }
559 
560   if (ctx->flags & IPMI_FLAGS_DEBUG_DUMP && send_len)
561     _api_lan_dump_rq (ctx,
562                       pkt,
563                       send_len,
564                       cmd,
565                       net_fn,
566                       group_extension,
567                       obj_cmd_rq);
568 
569   do
570     {
571       ret = ipmi_lan_sendto (ctx->io.outofband.sockfd,
572                              pkt,
573                              send_len,
574                              0,
575                              ctx->io.outofband.remote_host,
576                              ctx->io.outofband.remote_host_len);
577     } while (ret < 0 && errno == EINTR);
578 
579   if (ret < 0)
580     {
581       API_ERRNO_TO_API_ERRNUM (ctx, errno);
582       goto cleanup;
583     }
584 
585   if (gettimeofday (&ctx->io.outofband.last_send, NULL) < 0)
586     {
587       API_ERRNO_TO_API_ERRNUM (ctx, errno);
588       goto cleanup;
589     }
590 
591   rv = 0;
592  cleanup:
593   free (pkt);
594   return (rv);
595 }
596 
597 /* return receive length on success, 0 on no packet, -1 on error */
598 static int
_api_lan_cmd_recv(ipmi_ctx_t ctx,void * pkt,unsigned int pkt_len,unsigned int retransmission_count)599 _api_lan_cmd_recv (ipmi_ctx_t ctx,
600                    void *pkt,
601                    unsigned int pkt_len,
602                    unsigned int retransmission_count)
603 {
604   struct timeval recv_starttime;
605   int recv_len = 0;
606 
607   assert (ctx
608           && ctx->magic == IPMI_CTX_MAGIC
609           && (ctx->type == IPMI_DEVICE_LAN
610               || ctx->type == IPMI_DEVICE_LAN_2_0)
611           && ctx->io.outofband.sockfd
612           && pkt
613           && pkt_len);
614 
615   if (gettimeofday (&recv_starttime, NULL) < 0)
616     {
617       API_ERRNO_TO_API_ERRNUM (ctx, errno);
618       return (-1);
619     }
620 
621   recv_len = _api_lan_recvfrom (ctx,
622                                 pkt,
623                                 pkt_len,
624                                 retransmission_count,
625                                 &recv_starttime);
626 
627   if (!recv_len)
628     return (0); /* resend the request */
629 
630   /* achu & hliebig:
631    *
632    * Premise from ipmitool (http://ipmitool.sourceforge.net/)
633    *
634    * On some OSes (it seems Unixes), the behavior is to not return
635    * port denied errors up to the client for UDP responses (i.e. you
636    * need to timeout).  But on some OSes (it seems Windows), the
637    * behavior is to return port denied errors up to the user for UDP
638    * responses via ECONNRESET or ECONNREFUSED.
639    *
640    * If this were just the case, we could return or handle errors
641    * properly and move on.  However, it's not the case.
642    *
643    * According to Ipmitool, on some motherboards, both the OS and the
644    * BMC are capable of responding to an IPMI request.  That means you
645    * can get an ECONNRESET or ECONNREFUSED, then later on, get your
646    * real IPMI response.
647    *
648    * Our solution is copied from Ipmitool, we'll ignore some specific
649    * errors and try to read again.
650    *
651    * If the ECONNREFUSED or ECONNRESET is from the OS, but we will get
652    * an IPMI response later, the recvfrom later on gets the packet we
653    * want.
654    *
655    * If the ECONNREFUSED or ECONNRESET is from the OS but there is no
656    * BMC (or IPMI disabled, etc.), just do the recvfrom again to
657    * eventually get a timeout, which is the behavior we'd like.
658    */
659 
660   if (recv_len < 0
661       && (errno == ECONNRESET
662           || errno == ECONNREFUSED))
663     {
664       recv_len = _api_lan_recvfrom (ctx,
665                                     pkt,
666                                     pkt_len,
667                                     retransmission_count,
668                                     &recv_starttime);
669 
670       if (!recv_len)
671         return (0); /* resend the request */
672     }
673 
674   if (recv_len < 0)
675     {
676       API_ERRNO_TO_API_ERRNUM (ctx, errno);
677       return (-1);
678     }
679 
680   return (recv_len);
681 }
682 
683 /* < 0 - error
684  * == 1 good packet
685  * == 0 bad packet
686  */
687 static int
_api_lan_cmd_wrapper_verify_packet(ipmi_ctx_t ctx,unsigned int internal_workaround_flags,uint8_t authentication_type,int check_authentication_code,uint32_t * session_sequence_number,uint32_t session_id,uint8_t * rq_seq,const char * password,unsigned int password_len,fiid_obj_t obj_cmd_rs)688 _api_lan_cmd_wrapper_verify_packet (ipmi_ctx_t ctx,
689                                     unsigned int internal_workaround_flags,
690                                     uint8_t authentication_type,
691                                     int check_authentication_code,
692                                     uint32_t *session_sequence_number,
693                                     uint32_t session_id,
694                                     uint8_t *rq_seq,
695                                     const char *password,
696                                     unsigned int password_len,
697                                     fiid_obj_t obj_cmd_rs)
698 {
699   uint32_t rs_session_id;
700   uint32_t rs_session_sequence_number;
701   uint64_t val;
702   int rv = -1;
703   int ret;
704 
705   assert (ctx
706           && ctx->magic == IPMI_CTX_MAGIC
707           && (ctx->type == IPMI_DEVICE_LAN
708               || ctx->type == IPMI_DEVICE_LAN_2_0)
709           && ctx->io.outofband.sockfd
710           && IPMI_1_5_AUTHENTICATION_TYPE_VALID (authentication_type)
711           && !(password && password_len > IPMI_1_5_MAX_PASSWORD_LENGTH)
712           && fiid_obj_valid (obj_cmd_rs));
713 
714   if (FIID_OBJ_GET (ctx->io.outofband.rs.obj_lan_session_hdr,
715                     "session_id",
716                     &val) < 0)
717     {
718       API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, ctx->io.outofband.rs.obj_lan_session_hdr);
719       goto cleanup;
720     }
721   rs_session_id = val;
722 
723   if (session_id != rs_session_id)
724     {
725       /* IPMI Workaround (achu)
726        *
727        * Discovered on Tyan S2882 w/ m3289 BMC
728        *
729        * The remote BMC returns zeroes for the session id instead of the
730        * actual session id.  To work around this problem, we'll assume the
731        * session id is correct if it is equal to zero.
732        */
733       if ((ctx->workaround_flags_outofband & IPMI_WORKAROUND_FLAGS_OUTOFBAND_ACCEPT_SESSION_ID_ZERO)
734           && !rs_session_id)
735         /* you get a second chance - continue on checking */
736         ;
737       else
738         {
739 
740           /*
741            * IPMI Workaround
742            *
743            * Discovered on Xyratex HB-F8-SRAY
744            *
745            * The session ID is zero if there is an error.  So if there
746            * is a bad completion code, we'd rather fall through and
747            * continue.  So return "bad packet" if the completion code
748            * is < 0 or 1.
749            */
750           ret = ipmi_check_completion_code_success (obj_cmd_rs);
751           if (ret)
752             {
753               rv = 0;
754               goto cleanup;
755             }
756         }
757     }
758 
759   /* IPMI Workaround (achu)
760    *
761    * Discovered on Supermicro X9SCM-iiF, Supermicro X9DRi-F
762    *
763    * Checksums are computed incorrectly.
764    */
765   if (!(ctx->workaround_flags_outofband & IPMI_WORKAROUND_FLAGS_OUTOFBAND_NO_CHECKSUM_CHECK))
766     {
767       if ((ret = ipmi_lan_check_checksum (ctx->io.outofband.rs.obj_lan_msg_hdr,
768                                           obj_cmd_rs,
769                                           ctx->io.outofband.rs.obj_lan_msg_trlr)) < 0)
770         {
771           API_ERRNO_TO_API_ERRNUM (ctx, errno);
772           goto cleanup;
773         }
774 
775       if (!ret)
776         {
777           rv = 0;
778           goto cleanup;
779         }
780     }
781 
782   /* IPMI Workaround (achu)
783    *
784    * Discovered on Xyratex HB-F8-SRAY
785    *
786    * For some reason, the authentication code is always blank when
787    * using "Straight Password Key".
788    *
789    * Discovered on Intel Windmill/Quanta Winterfell/Wiwynn Windmill
790    *
791    * Hash is incorrect, unknown why calculation is incorrect.
792    */
793 
794   if (check_authentication_code
795       && !(ctx->flags & IPMI_FLAGS_IGNORE_AUTHENTICATION_CODE)
796       && !(ctx->workaround_flags_outofband & IPMI_WORKAROUND_FLAGS_OUTOFBAND_NO_AUTH_CODE_CHECK))
797     {
798       if ((ret = ipmi_lan_check_session_authentication_code (ctx->io.outofband.rs.obj_lan_session_hdr,
799                                                              ctx->io.outofband.rs.obj_lan_msg_hdr,
800                                                              obj_cmd_rs,
801                                                              ctx->io.outofband.rs.obj_lan_msg_trlr,
802                                                              authentication_type,
803                                                              password,
804                                                              password_len)) < 0)
805         {
806           API_ERRNO_TO_API_ERRNUM (ctx, errno);
807           goto cleanup;
808         }
809 
810       /* IPMI Workaround (achu)
811        *
812        * Discovered on Dell PowerEdge 2850
813        *
814        * When per-message authentication is disabled, and we send a
815        * message to a remote machine with auth-type none, the Dell
816        * motherboard will respond with a message with the auth-type used
817        * in the activate session stage and the appropriate authcode. So
818        * here is our second session-authcode check attempt under these
819        * circumstances.
820        */
821 
822       if ((internal_workaround_flags & IPMI_INTERNAL_WORKAROUND_FLAGS_CHECK_UNEXPECTED_AUTHCODE)
823           && !ret)
824         {
825           if ((ret = ipmi_lan_check_session_authentication_code (ctx->io.outofband.rs.obj_lan_session_hdr,
826                                                                  ctx->io.outofband.rs.obj_lan_msg_hdr,
827                                                                  obj_cmd_rs,
828                                                                  ctx->io.outofband.rs.obj_lan_msg_trlr,
829                                                                  authentication_type,
830                                                                  password,
831                                                                  password_len)) < 0)
832             {
833               API_ERRNO_TO_API_ERRNUM (ctx, errno);
834               goto cleanup;
835             }
836         }
837 
838       if (!ret)
839         {
840           rv = 0;
841           goto cleanup;
842         }
843     }
844 
845   if (session_sequence_number)
846     {
847       if (FIID_OBJ_GET (ctx->io.outofband.rs.obj_lan_session_hdr,
848                         "session_sequence_number",
849                         &val) < 0)
850         {
851           API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, ctx->io.outofband.rs.obj_lan_session_hdr);
852           goto cleanup;
853         }
854       rs_session_sequence_number = val;
855 
856       if ((ret = _ipmi_check_session_sequence_number (ctx,
857                                                       rs_session_sequence_number)) < 0)
858         {
859           API_ERRNO_TO_API_ERRNUM (ctx, errno);
860           goto cleanup;
861         }
862 
863       if (!ret)
864         {
865           rv = 0;
866           goto cleanup;
867         }
868     }
869 
870   if ((ret = ipmi_lan_check_rq_seq (ctx->io.outofband.rs.obj_lan_msg_hdr,
871                                     (rq_seq) ? *rq_seq : 0)) < 0)
872     {
873       API_ERRNO_TO_API_ERRNUM (ctx, errno);
874       goto cleanup;
875     }
876 
877   if (!ret)
878     {
879       rv = 0;
880       goto cleanup;
881     }
882 
883   rv = 1;
884  cleanup:
885   return (rv);
886 }
887 
888 int
api_lan_cmd_wrapper(ipmi_ctx_t ctx,unsigned int internal_workaround_flags,uint8_t lun,uint8_t net_fn,uint8_t authentication_type,int check_authentication_code,uint32_t * session_sequence_number,uint32_t session_id,uint8_t * rq_seq,const char * password,unsigned int password_len,fiid_obj_t obj_cmd_rq,fiid_obj_t obj_cmd_rs)889 api_lan_cmd_wrapper (ipmi_ctx_t ctx,
890                      unsigned int internal_workaround_flags,
891                      uint8_t lun,
892                      uint8_t net_fn,
893                      uint8_t authentication_type,
894                      int check_authentication_code,
895                      uint32_t *session_sequence_number,
896                      uint32_t session_id,
897                      uint8_t *rq_seq,
898                      const char *password,
899                      unsigned int password_len,
900                      fiid_obj_t obj_cmd_rq,
901                      fiid_obj_t obj_cmd_rs)
902 {
903   int recv_len, ret, rv = -1;
904   unsigned int retransmission_count = 0;
905   uint8_t pkt[IPMI_MAX_PKT_LEN];
906   struct socket_to_close *sockets = NULL;
907   uint8_t cmd = 0;             /* used for debugging */
908   uint8_t group_extension = 0; /* used for debugging */
909   uint64_t val;
910   unsigned int intf_flags = IPMI_INTERFACE_FLAGS_DEFAULT;
911 
912   assert (ctx
913           && ctx->magic == IPMI_CTX_MAGIC
914           && (ctx->type == IPMI_DEVICE_LAN
915               || ctx->type == IPMI_DEVICE_LAN_2_0)
916           && ctx->io.outofband.sockfd
917           && IPMI_BMC_LUN_VALID (lun)
918           && IPMI_NET_FN_VALID (net_fn)
919           && IPMI_1_5_AUTHENTICATION_TYPE_VALID (authentication_type)
920           && !(password && password_len > IPMI_1_5_MAX_PASSWORD_LENGTH)
921           && fiid_obj_valid (obj_cmd_rq)
922           && fiid_obj_packet_valid (obj_cmd_rq) == 1
923           && fiid_obj_valid (obj_cmd_rs));
924 
925   if (ctx->flags & IPMI_FLAGS_NO_LEGAL_CHECK)
926     intf_flags |= IPMI_INTERFACE_FLAGS_NO_LEGAL_CHECK;
927 
928   if (!ctx->io.outofband.last_received.tv_sec
929       && !ctx->io.outofband.last_received.tv_usec)
930     {
931       if (gettimeofday (&ctx->io.outofband.last_received, NULL) < 0)
932         {
933           API_ERRNO_TO_API_ERRNUM (ctx, errno);
934           return (-1);
935         }
936     }
937 
938   if (ctx->flags & IPMI_FLAGS_DEBUG_DUMP)
939     {
940       /* ignore error, continue on */
941       if (FIID_OBJ_GET (obj_cmd_rq,
942                         "cmd",
943                         &val) < 0)
944         API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_cmd_rq);
945       else
946         cmd = val;
947 
948       if (IPMI_NET_FN_GROUP_EXTENSION (net_fn))
949         {
950           /* ignore error, continue on */
951           if (FIID_OBJ_GET (obj_cmd_rq,
952                             "group_extension_identification",
953                             &val) < 0)
954             API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_cmd_rq);
955           else
956             group_extension = val;
957         }
958     }
959 
960   if (_api_lan_cmd_send (ctx,
961                          lun,
962                          net_fn,
963                          authentication_type,
964                          (session_sequence_number) ? *session_sequence_number : 0,
965                          session_id,
966                          (rq_seq) ? *rq_seq : 0,
967                          password,
968                          password_len,
969                          cmd,  /* for debug dumping */
970                          group_extension,  /* for debug dumping */
971                          obj_cmd_rq) < 0)
972     goto cleanup;
973 
974   while (1)
975     {
976       if ((ret = _session_timed_out (ctx)) < 0)
977         break;
978 
979       if (ret)
980         {
981           if (ctx->flags & IPMI_FLAGS_NOSESSION)
982             API_SET_ERRNUM (ctx, IPMI_ERR_MESSAGE_TIMEOUT);
983           else
984             API_SET_ERRNUM (ctx, IPMI_ERR_SESSION_TIMEOUT);
985           break;
986         }
987 
988       if ((recv_len = _api_lan_cmd_recv (ctx,
989                                          pkt,
990                                          IPMI_MAX_PKT_LEN,
991                                          retransmission_count)) < 0)
992         break;
993 
994       if (!recv_len)
995         {
996           /* ignore timeout, just cleanly close session */
997           if (internal_workaround_flags & IPMI_INTERNAL_WORKAROUND_FLAGS_CLOSE_SESSION_SKIP_RETRANSMIT)
998             {
999               rv = 0;
1000               break;
1001             }
1002 
1003           if (session_sequence_number)
1004             (*session_sequence_number)++;
1005           if (rq_seq)
1006             *rq_seq = ((*rq_seq) + 1) % (IPMI_LAN_REQUESTER_SEQUENCE_NUMBER_MAX + 1);
1007 
1008           retransmission_count++;
1009 
1010           /* IPMI Workaround (achu)
1011            *
1012            * Discovered on Intel Tiger4 (SR870BN4)
1013            *
1014            * If the reply from a previous Get Session Challenge request is
1015            * lost on the network, the following retransmission will make
1016            * the BMC confused and it will not respond to future packets.
1017            *
1018            * The problem seems to exist only when the retransmitted packet
1019            * is transmitted from the same source port.  Therefore, the fix
1020            * is to send the retransmission from a different source port.
1021            * So we'll create a new socket, re-bind to an ephemereal port
1022            * (guaranteeing us a brand new port), and store this new
1023            * socket.
1024            *
1025            * In the event we need to resend this packet multiple times, we
1026            * do not want the chance that old ports will be used again.  We
1027            * store the old file descriptrs (which are bound to the old
1028            * ports) on a list, and close all of them after we have gotten
1029            * past the Get Session Challenge phase of the protocol.
1030            */
1031           if (internal_workaround_flags & IPMI_INTERNAL_WORKAROUND_FLAGS_GET_SESSION_CHALLENGE)
1032             {
1033               struct socket_to_close *s;
1034 
1035               if (!(s = (struct socket_to_close *)malloc (sizeof (struct socket_to_close))))
1036                 {
1037                   API_SET_ERRNUM (ctx, IPMI_ERR_OUT_OF_MEMORY);
1038                   goto cleanup;
1039                 }
1040               s->fd = ctx->io.outofband.sockfd;
1041               s->next = sockets;
1042               sockets = s;
1043 
1044               if ((ctx->io.outofband.sockfd = socket (ctx->io.outofband.srcaddr->sa_family,
1045                                                       SOCK_DGRAM,
1046                                                       0)) < 0)
1047                 {
1048                   API_ERRNO_TO_API_ERRNUM (ctx, errno);
1049                   goto cleanup;
1050                 }
1051 
1052               if (bind (ctx->io.outofband.sockfd,
1053                         ctx->io.outofband.srcaddr,
1054                         ctx->io.outofband.srcaddr_len) < 0)
1055                 {
1056                   API_ERRNO_TO_API_ERRNUM (ctx, errno);
1057                   goto cleanup;
1058                 }
1059             }
1060 
1061           if (_api_lan_cmd_send (ctx,
1062                                  lun,
1063                                  net_fn,
1064                                  authentication_type,
1065                                  (session_sequence_number) ? *session_sequence_number : 0,
1066                                  session_id,
1067                                  (rq_seq) ? *rq_seq : 0,
1068                                  password,
1069                                  password_len,
1070                                  cmd,  /* for debug dumping */
1071                                  group_extension,  /* for debug dumping */
1072                                  obj_cmd_rq) < 0)
1073             goto cleanup;
1074 
1075           continue;
1076         }
1077 
1078       /* else received a packet */
1079 
1080       /* its ok to use the "request" net_fn, dump code doesn't care */
1081       if (ctx->flags & IPMI_FLAGS_DEBUG_DUMP)
1082         _api_lan_dump_rs (ctx,
1083                           pkt,
1084                           recv_len,
1085                           cmd,
1086                           net_fn,
1087                           group_extension,
1088                           obj_cmd_rs);
1089 
1090       if ((ret = unassemble_ipmi_lan_pkt (pkt,
1091                                           recv_len,
1092                                           ctx->io.outofband.rs.obj_rmcp_hdr,
1093                                           ctx->io.outofband.rs.obj_lan_session_hdr,
1094                                           ctx->io.outofband.rs.obj_lan_msg_hdr,
1095                                           obj_cmd_rs,
1096                                           ctx->io.outofband.rs.obj_lan_msg_trlr,
1097                                           intf_flags)) < 0)
1098         {
1099           API_ERRNO_TO_API_ERRNUM (ctx, errno);
1100           return (-1);
1101         }
1102 
1103       if (!ret)
1104         continue;
1105 
1106       if ((ret = _api_lan_cmd_wrapper_verify_packet (ctx,
1107                                                      internal_workaround_flags,
1108                                                      authentication_type,
1109                                                      check_authentication_code,
1110                                                      session_sequence_number,
1111                                                      session_id,
1112                                                      rq_seq,
1113                                                      password,
1114                                                      password_len,
1115                                                      obj_cmd_rs)) < 0)
1116         goto cleanup;
1117 
1118       if (!ret)
1119         continue;
1120 
1121       if (gettimeofday (&(ctx->io.outofband.last_received), NULL) < 0)
1122         {
1123           API_ERRNO_TO_API_ERRNUM (ctx, errno);
1124           return (-1);
1125         }
1126 
1127       rv = 0;
1128       break;
1129     }
1130 
1131  cleanup:
1132   if (session_sequence_number)
1133     (*session_sequence_number)++;
1134   if (rq_seq)
1135     *rq_seq = ((*rq_seq) + 1) % (IPMI_LAN_REQUESTER_SEQUENCE_NUMBER_MAX + 1);
1136   while (sockets)
1137     {
1138       /* ignore potential error, cleanup path */
1139       close (sockets->fd);
1140       sockets = sockets->next;
1141     }
1142   return (rv);
1143 }
1144 
1145 /* see workaround _ipmi_check_ipmb_out_of_order() regarding obj_rs & obj_rs_errnum pointer */
1146 static int
_ipmi_cmd_send_ipmb(ipmi_ctx_t ctx,fiid_obj_t obj_cmd_rq,fiid_obj_t * obj_rs,ipmi_errnum_type_t * obj_rs_errnum)1147 _ipmi_cmd_send_ipmb (ipmi_ctx_t ctx,
1148                      fiid_obj_t obj_cmd_rq,
1149                      fiid_obj_t *obj_rs,
1150                      ipmi_errnum_type_t *obj_rs_errnum)
1151 {
1152   struct ipmi_ctx_target target_save;
1153   uint8_t tbuf[IPMI_MAX_PKT_LEN];
1154   fiid_obj_t obj_ipmb_msg_hdr_rq = NULL;
1155   fiid_obj_t obj_ipmb_msg_rq = NULL;
1156   fiid_obj_t obj_send_cmd_rs = NULL;
1157   int len, ret, rv = -1;
1158 
1159   assert (ctx
1160           && ctx->magic == IPMI_CTX_MAGIC
1161           && (ctx->type == IPMI_DEVICE_LAN
1162               || ctx->type == IPMI_DEVICE_LAN_2_0)
1163           && ctx->io.outofband.sockfd
1164           && fiid_obj_valid (obj_cmd_rq)
1165           && fiid_obj_packet_valid (obj_cmd_rq) == 1);
1166 
1167   (*obj_rs_errnum) = IPMI_ERR_SUCCESS;
1168 
1169   if (!(obj_ipmb_msg_hdr_rq = fiid_obj_create (tmpl_ipmb_msg_hdr_rq)))
1170     {
1171       API_ERRNO_TO_API_ERRNUM (ctx, errno);
1172       goto cleanup;
1173     }
1174   if (!(obj_ipmb_msg_rq = fiid_obj_create (tmpl_ipmb_msg)))
1175     {
1176       API_ERRNO_TO_API_ERRNUM (ctx, errno);
1177       goto cleanup;
1178     }
1179   if (!(obj_send_cmd_rs = fiid_obj_create (tmpl_cmd_send_message_rs)))
1180     {
1181       API_ERRNO_TO_API_ERRNUM (ctx, errno);
1182       goto cleanup;
1183     }
1184 
1185   if (fill_ipmb_msg_hdr (ctx->target.rs_addr,
1186                          ctx->target.net_fn,
1187                          ctx->target.lun,
1188                          IPMI_SLAVE_ADDRESS_BMC,
1189                          IPMI_BMC_IPMB_LUN_BMC,
1190                          ctx->io.outofband.rq_seq,
1191                          obj_ipmb_msg_hdr_rq) < 0)
1192     {
1193       API_ERRNO_TO_API_ERRNUM (ctx, errno);
1194       goto cleanup;
1195     }
1196 
1197   if (assemble_ipmi_ipmb_msg (obj_ipmb_msg_hdr_rq,
1198                               obj_cmd_rq,
1199                               obj_ipmb_msg_rq,
1200                               IPMI_INTERFACE_FLAGS_DEFAULT) < 0)
1201     {
1202       API_ERRNO_TO_API_ERRNUM (ctx, errno);
1203       goto cleanup;
1204     }
1205 
1206   if ((len = fiid_obj_get_all (obj_ipmb_msg_rq,
1207                                tbuf,
1208                                IPMI_MAX_PKT_LEN)) < 0)
1209     {
1210       API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_ipmb_msg_rq);
1211       goto cleanup;
1212     }
1213 
1214   /* send_message will send to the BMC, so clear out target information */
1215   memcpy (&target_save, &ctx->target, sizeof (target_save));
1216   ctx->target.channel_number_is_set = 0;
1217   ctx->target.rs_addr_is_set = 0;
1218 
1219   ret = ipmi_cmd_send_message (ctx,
1220                                target_save.channel_number,
1221                                IPMI_SEND_MESSAGE_AUTHENTICATION_NOT_REQUIRED,
1222                                IPMI_SEND_MESSAGE_ENCRYPTION_NOT_REQUIRED,
1223                                IPMI_SEND_MESSAGE_TRACKING_OPERATION_TRACKING_REQUEST,
1224                                tbuf,
1225                                len,
1226                                obj_send_cmd_rs);
1227 
1228   /* restore target info */
1229   memcpy (&ctx->target, &target_save, sizeof (target_save));
1230 
1231   if (ret < 0)
1232     {
1233       uint64_t cmd;
1234 
1235       /* Check for potential out of order condition.  See
1236        * _ipmi_check_ipmb_out_of_order() for more details.
1237        *
1238        * Basically, we will return success if the completion code is
1239        * one in which we would expect another message to arrive.
1240        */
1241       if (FIID_OBJ_GET (obj_send_cmd_rs, "cmd", &cmd) == 1)
1242         {
1243           if (cmd != IPMI_CMD_SEND_MESSAGE
1244               && ipmi_check_completion_code (obj_send_cmd_rs,
1245                                              IPMI_COMP_CODE_COMMAND_SUCCESS) == 0)
1246             {
1247               TRACE_MSG_OUT ("accept out-of-order with bad completion code", 0);
1248               (*obj_rs_errnum) = ctx->errnum;
1249               ctx->errnum = IPMI_ERR_SUCCESS;
1250               goto out_of_order_workaround;
1251             }
1252         }
1253 
1254       goto cleanup;
1255     }
1256 
1257  out_of_order_workaround:
1258   /* "pretend" a request was just sent */
1259   if (gettimeofday (&ctx->io.outofband.last_send, NULL) < 0)
1260     {
1261       API_ERRNO_TO_API_ERRNUM (ctx, errno);
1262       goto cleanup;
1263     }
1264 
1265   if (obj_rs)
1266     {
1267       (*obj_rs) = obj_send_cmd_rs;
1268       obj_send_cmd_rs = NULL;
1269     }
1270 
1271   rv = 0;
1272  cleanup:
1273   fiid_obj_destroy (obj_ipmb_msg_hdr_rq);
1274   fiid_obj_destroy (obj_ipmb_msg_rq);
1275   fiid_obj_destroy (obj_send_cmd_rs);
1276   return (rv);
1277 }
1278 
1279 static int
_ipmi_check_ipmb_out_of_order(ipmi_ctx_t ctx,fiid_obj_t obj_cmd_rq,fiid_obj_t obj_cmd_rs,fiid_obj_t obj_send_cmd_rs,ipmi_errnum_type_t obj_rs_errnum)1280 _ipmi_check_ipmb_out_of_order (ipmi_ctx_t ctx,
1281                                fiid_obj_t obj_cmd_rq,
1282                                fiid_obj_t obj_cmd_rs,
1283                                fiid_obj_t obj_send_cmd_rs,
1284                                ipmi_errnum_type_t obj_rs_errnum)
1285 {
1286   uint8_t buf[IPMI_MAX_PKT_LEN];
1287   uint64_t val;
1288   uint8_t cmd_rq;
1289   uint8_t cmd_rs;
1290   uint8_t send_cmd_rs;
1291   int len;
1292 
1293   /* There is always a small chance that the network response to
1294    * the initial ipmb send message could be out-of-ordered with
1295    * the "real" response that we want.
1296    *
1297    * XXX: Add a mechanism to re-dump the full packet?
1298    */
1299 
1300   if ((len = fiid_obj_get_all (obj_cmd_rs, buf, IPMI_MAX_PKT_LEN)) < 0)
1301     return (0);
1302 
1303   if (!len)
1304     return (0);
1305 
1306   /* get "cmd" for the response.  Don't use fiid_obj_get(), b/c this could be a raw packet */
1307   cmd_rs = buf[0];
1308 
1309   /* if cmd_rs isn't send message, assume things weren't out of order
1310    * and all is good
1311    */
1312   if (cmd_rs != IPMI_CMD_SEND_MESSAGE)
1313     return (0);
1314 
1315   /* else, we've probably got an out of order */
1316 
1317   if ((len = fiid_obj_get_all (obj_cmd_rq, buf, IPMI_MAX_PKT_LEN)) < 0)
1318     return (0);
1319 
1320   if (!len)
1321     return (0);
1322 
1323   cmd_rq = buf[0];
1324 
1325   if ((len = fiid_obj_get_all (obj_send_cmd_rs, buf, IPMI_MAX_PKT_LEN)) < 0)
1326     return (0);
1327 
1328   if (!len)
1329     return (0);
1330 
1331   send_cmd_rs = buf[0];
1332 
1333   /* if the command sent in the request is the same as the command
1334    * returned in the send message response, assume we've got an out of
1335    * order
1336    */
1337 
1338   if (cmd_rq != send_cmd_rs)
1339     return (0);
1340 
1341   /* this is the one function we can't fail */
1342   if (fiid_obj_set_all (obj_cmd_rs, buf, len) < 0) {
1343     API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_cmd_rs);
1344     return (-1);
1345   }
1346 
1347   TRACE_MSG_OUT ("reversed obj_cmd responses", 0);
1348 
1349   if (obj_rs_errnum != IPMI_ERR_SUCCESS) {
1350     API_SET_ERRNUM (ctx, obj_rs_errnum);
1351     return (-1);
1352   }
1353 
1354   return (0);
1355 }
1356 
1357 int
api_lan_cmd_wrapper_ipmb(ipmi_ctx_t ctx,fiid_obj_t obj_cmd_rq,fiid_obj_t obj_cmd_rs)1358 api_lan_cmd_wrapper_ipmb (ipmi_ctx_t ctx,
1359                           fiid_obj_t obj_cmd_rq,
1360                           fiid_obj_t obj_cmd_rs)
1361 {
1362   int recv_len, ret, rv = -1;
1363   unsigned int retransmission_count = 0;
1364   uint8_t pkt[IPMI_MAX_PKT_LEN];
1365   uint8_t cmd = 0;             /* used for debugging */
1366   uint8_t group_extension = 0; /* used for debugging */
1367   uint8_t rq_seq_orig;
1368   uint64_t val;
1369   unsigned int intf_flags = IPMI_INTERFACE_FLAGS_DEFAULT;
1370   fiid_obj_t obj_send_rs = NULL;
1371   ipmi_errnum_type_t obj_rs_errnum;
1372 
1373   assert (ctx
1374           && ctx->magic == IPMI_CTX_MAGIC
1375           && (ctx->type == IPMI_DEVICE_LAN
1376               || ctx->type == IPMI_DEVICE_LAN_2_0)
1377           && ctx->io.outofband.sockfd
1378           && fiid_obj_valid (obj_cmd_rq)
1379           && fiid_obj_packet_valid (obj_cmd_rq) == 1
1380           && fiid_obj_valid (obj_cmd_rs));
1381 
1382   if (ctx->flags & IPMI_FLAGS_NO_LEGAL_CHECK)
1383     intf_flags |= IPMI_INTERFACE_FLAGS_NO_LEGAL_CHECK;
1384 
1385   if (ctx->flags & IPMI_FLAGS_DEBUG_DUMP)
1386     {
1387       /* ignore error, continue on */
1388       if (FIID_OBJ_GET (obj_cmd_rq,
1389                         "cmd",
1390                         &val) < 0)
1391         API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_cmd_rq);
1392       else
1393         cmd = val;
1394 
1395       if (IPMI_NET_FN_GROUP_EXTENSION (ctx->target.net_fn))
1396         {
1397           /* ignore error, continue on */
1398           if (FIID_OBJ_GET (obj_cmd_rq,
1399                             "group_extension_identification",
1400                             &val) < 0)
1401             API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_cmd_rq);
1402           else
1403             group_extension = val;
1404         }
1405     }
1406 
1407   /* for debugging */
1408   ctx->tmpl_ipmb_cmd_rq = fiid_obj_template (obj_cmd_rq);
1409   ctx->tmpl_ipmb_cmd_rs = fiid_obj_template (obj_cmd_rs);
1410 
1411   /* ipmb response packet will use the request sequence number from
1412    * the earlier packet.  Save it for verification.
1413    */
1414 
1415   rq_seq_orig = ctx->io.outofband.rq_seq;
1416 
1417   if (_ipmi_cmd_send_ipmb (ctx,
1418                            obj_cmd_rq,
1419                            &obj_send_rs,
1420                            &obj_rs_errnum) < 0)
1421     goto cleanup;
1422 
1423   while (1)
1424     {
1425       uint8_t authentication_type;
1426       unsigned int internal_workaround_flags = 0;
1427 
1428       if ((ret = _session_timed_out (ctx)) < 0)
1429         break;
1430 
1431       if (ret)
1432         {
1433           API_SET_ERRNUM (ctx, IPMI_ERR_SESSION_TIMEOUT);
1434           break;
1435         }
1436 
1437       if ((recv_len = _api_lan_cmd_recv (ctx,
1438                                          pkt,
1439                                          IPMI_MAX_PKT_LEN,
1440                                          retransmission_count)) < 0)
1441         break;
1442 
1443       if (!recv_len)
1444         {
1445           retransmission_count++;
1446 
1447           /* don't increment sequence numbers, will be done in _ipmi_cmd_send_ipmb */
1448 
1449           /* ipmb response packet will use the request sequence number from
1450            * the earlier packet.  Save it for verification.
1451            */
1452 
1453           rq_seq_orig = ctx->io.outofband.rq_seq;
1454 
1455           if (obj_send_rs) {
1456             fiid_obj_destroy (obj_send_rs);
1457             obj_send_rs = NULL;
1458           }
1459 
1460           if (_ipmi_cmd_send_ipmb (ctx,
1461                                    obj_cmd_rq,
1462                                    &obj_send_rs,
1463                                    &obj_rs_errnum) < 0)
1464             goto cleanup;
1465 
1466           continue;
1467         }
1468 
1469       /* else received a packet */
1470 
1471       /* its ok to use the "request" net_fn, dump code doesn't care */
1472       if (ctx->flags & IPMI_FLAGS_DEBUG_DUMP)
1473         _api_lan_dump_rs (ctx,
1474                           pkt,
1475                           recv_len,
1476                           cmd,
1477                           ctx->target.net_fn,
1478                           group_extension,
1479                           obj_cmd_rs);
1480 
1481       if ((ret = unassemble_ipmi_lan_pkt (pkt,
1482                                           recv_len,
1483                                           ctx->io.outofband.rs.obj_rmcp_hdr,
1484                                           ctx->io.outofband.rs.obj_lan_session_hdr,
1485                                           ctx->io.outofband.rs.obj_lan_msg_hdr,
1486                                           obj_cmd_rs,
1487                                           ctx->io.outofband.rs.obj_lan_msg_trlr,
1488                                           intf_flags)) < 0)
1489         {
1490           API_ERRNO_TO_API_ERRNUM (ctx, errno);
1491           return (-1);
1492         }
1493 
1494       if (!ret)
1495         continue;
1496 
1497       api_lan_cmd_get_session_parameters (ctx,
1498                                           &authentication_type,
1499                                           &internal_workaround_flags);
1500 
1501       if ((ret = _api_lan_cmd_wrapper_verify_packet (ctx,
1502                                                      internal_workaround_flags,
1503                                                      authentication_type,
1504                                                      1, /* always check auth code at this point */
1505                                                      &(ctx->io.outofband.session_sequence_number),
1506                                                      ctx->io.outofband.session_id,
1507                                                      &rq_seq_orig,
1508                                                      ctx->io.outofband.password,
1509                                                      IPMI_1_5_MAX_PASSWORD_LENGTH,
1510                                                      obj_cmd_rs)) < 0)
1511         goto cleanup;
1512 
1513       if (!ret)
1514         continue;
1515 
1516       if (gettimeofday (&(ctx->io.outofband.last_received), NULL) < 0)
1517         {
1518           API_ERRNO_TO_API_ERRNUM (ctx, errno);
1519           goto cleanup;
1520         }
1521 
1522       if (_ipmi_check_ipmb_out_of_order (ctx,
1523                                          obj_cmd_rq,
1524                                          obj_cmd_rs,
1525                                          obj_send_rs,
1526                                          obj_rs_errnum) < 0)
1527         goto cleanup;
1528 
1529       rv = 0;
1530       break;
1531     }
1532 
1533  cleanup:
1534   ctx->io.outofband.session_sequence_number++;
1535   /* rq_seq already incremented via _ipmi_cmd_send_ipmb call */
1536   fiid_template_free (ctx->tmpl_ipmb_cmd_rq);
1537   ctx->tmpl_ipmb_cmd_rq = NULL;
1538   fiid_template_free (ctx->tmpl_ipmb_cmd_rs);
1539   ctx->tmpl_ipmb_cmd_rs = NULL;
1540   fiid_obj_destroy (obj_send_rs);
1541 
1542   return (rv);
1543 }
1544 
1545 static int
_api_lan_rq_seq_init(ipmi_ctx_t ctx)1546 _api_lan_rq_seq_init (ipmi_ctx_t ctx)
1547 {
1548   unsigned int seedp;
1549 
1550   assert (ctx
1551           && ctx->magic == IPMI_CTX_MAGIC
1552           && ctx->io.outofband.sockfd
1553           && (ctx->type == IPMI_DEVICE_LAN
1554               || ctx->type == IPMI_DEVICE_LAN_2_0));
1555 
1556   /* Random number generation */
1557   seedp = (unsigned int) clock () + (unsigned int) time (NULL);
1558   srand (seedp);
1559 
1560   ctx->io.outofband.rq_seq = (uint8_t)((double)(IPMI_LAN_REQUESTER_SEQUENCE_NUMBER_MAX) * (rand ()/(RAND_MAX + 1.0)));
1561   return (0);
1562 }
1563 
1564 int
api_lan_open_session(ipmi_ctx_t ctx)1565 api_lan_open_session (ipmi_ctx_t ctx)
1566 {
1567   fiid_obj_t obj_cmd_rq = NULL;
1568   fiid_obj_t obj_cmd_rs = NULL;
1569   uint8_t authentication_type;
1570   uint32_t temp_session_id = 0;
1571   uint8_t challenge_string[IPMI_CHALLENGE_STRING_LENGTH];
1572   int challenge_string_len;
1573   uint32_t initial_outbound_sequence_number = 0;
1574   char *tmp_username_ptr = NULL;
1575   char *tmp_password_ptr = NULL;
1576   int ret, rv = -1;
1577   uint64_t val;
1578 
1579   assert (ctx
1580           && ctx->magic == IPMI_CTX_MAGIC
1581           && ctx->io.outofband.sockfd
1582           && ctx->type == IPMI_DEVICE_LAN
1583           && strlen (ctx->io.outofband.username) <= IPMI_MAX_USER_NAME_LENGTH
1584           && strlen (ctx->io.outofband.password) <= IPMI_1_5_MAX_PASSWORD_LENGTH
1585           && IPMI_1_5_AUTHENTICATION_TYPE_VALID (ctx->io.outofband.authentication_type)
1586           && IPMI_PRIVILEGE_LEVEL_VALID (ctx->io.outofband.privilege_level));
1587 
1588   if (_api_lan_rq_seq_init (ctx) < 0)
1589     goto cleanup;
1590 
1591   if (ctx->flags & IPMI_FLAGS_NOSESSION)
1592     {
1593       ctx->io.outofband.authentication_type = IPMI_AUTHENTICATION_TYPE_NONE;
1594       goto out;
1595     }
1596 
1597   if (!(obj_cmd_rq = fiid_obj_create (tmpl_cmd_get_channel_authentication_capabilities_rq)))
1598     {
1599       API_ERRNO_TO_API_ERRNUM (ctx, errno);
1600       goto cleanup;
1601     }
1602   if (!(obj_cmd_rs = fiid_obj_create (tmpl_cmd_get_channel_authentication_capabilities_rs)))
1603     {
1604       API_ERRNO_TO_API_ERRNUM (ctx, errno);
1605       goto cleanup;
1606     }
1607 
1608   if (fill_cmd_get_channel_authentication_capabilities (IPMI_CHANNEL_NUMBER_CURRENT_CHANNEL,
1609                                                         ctx->io.outofband.privilege_level,
1610                                                         IPMI_GET_IPMI_V15_DATA,
1611                                                         obj_cmd_rq) < 0)
1612     {
1613       API_ERRNO_TO_API_ERRNUM (ctx, errno);
1614       goto cleanup;
1615     }
1616 
1617   if (api_lan_cmd_wrapper (ctx,
1618                            0,
1619                            IPMI_BMC_IPMB_LUN_BMC,
1620                            IPMI_NET_FN_APP_RQ,
1621                            IPMI_AUTHENTICATION_TYPE_NONE,
1622                            0,
1623                            NULL,
1624                            0,
1625                            &(ctx->io.outofband.rq_seq),
1626                            NULL,
1627                            0,
1628                            obj_cmd_rq,
1629                            obj_cmd_rs) < 0)
1630     {
1631       /* at this point in the protocol, we set a connection timeout */
1632       if (ctx->errnum == IPMI_ERR_SESSION_TIMEOUT)
1633         API_SET_ERRNUM (ctx, IPMI_ERR_CONNECTION_TIMEOUT);
1634       goto cleanup;
1635     }
1636 
1637   /* IPMI Workaround (achu)
1638    *
1639    * Discovered on an ASUS P5M2 motherboard.
1640    *
1641    * Also seen on Intel X38ML motherboard.
1642    *
1643    * The ASUS motherboard reports incorrect settings of anonymous
1644    * vs. null vs non-null username capabilities.  The workaround is to
1645    * skip these checks.
1646    */
1647   if (!(ctx->workaround_flags_outofband & IPMI_WORKAROUND_FLAGS_OUTOFBAND_AUTHENTICATION_CAPABILITIES))
1648     {
1649       if (strlen (ctx->io.outofband.username))
1650         tmp_username_ptr = ctx->io.outofband.username;
1651 
1652       if (strlen (ctx->io.outofband.password))
1653         tmp_password_ptr = ctx->io.outofband.password;
1654 
1655       if ((ret = ipmi_check_authentication_capabilities_username (tmp_username_ptr,
1656                                                                   tmp_password_ptr,
1657                                                                   obj_cmd_rs)) < 0)
1658         {
1659           API_ERRNO_TO_API_ERRNUM (ctx, errno);
1660           goto cleanup;
1661         }
1662 
1663       if (!ret)
1664         {
1665           ctx->errnum = IPMI_ERR_USERNAME_INVALID;
1666           goto cleanup;
1667         }
1668     }
1669 
1670   /* IPMI Workaround (achu)
1671    *
1672    * Discovered on IBM eServer 325
1673    *
1674    * The remote BMC ignores if permsg authentiction is enabled
1675    * or disabled.  So we need to force it no matter what.
1676    */
1677   if (!(ctx->workaround_flags_outofband & IPMI_WORKAROUND_FLAGS_OUTOFBAND_FORCE_PERMSG_AUTHENTICATION))
1678     {
1679       if (FIID_OBJ_GET (obj_cmd_rs,
1680                         "authentication_status.per_message_authentication",
1681                         &val) < 0)
1682         {
1683           API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_cmd_rs);
1684           goto cleanup;
1685         }
1686       ctx->io.outofband.per_msg_auth_disabled = val;
1687     }
1688   else
1689     ctx->io.outofband.per_msg_auth_disabled = 0;
1690 
1691   /* IPMI Workaround (achu)
1692    *
1693    * Not discovered yet, assume some motherboard will have it some
1694    * day.
1695    *
1696    * Authentication capabilities flags are not listed properly in the
1697    * response.  The workaround is to skip these checks.
1698    */
1699   if (!(ctx->workaround_flags_outofband & IPMI_WORKAROUND_FLAGS_OUTOFBAND_AUTHENTICATION_CAPABILITIES))
1700     {
1701       if ((ret = ipmi_check_authentication_capabilities_authentication_type (ctx->io.outofband.authentication_type,
1702                                                                              obj_cmd_rs)) < 0)
1703         {
1704           API_ERRNO_TO_API_ERRNUM (ctx, errno);
1705           goto cleanup;
1706         }
1707 
1708       if (!ret)
1709         {
1710           API_SET_ERRNUM (ctx, IPMI_ERR_AUTHENTICATION_TYPE_UNAVAILABLE);
1711           goto cleanup;
1712         }
1713     }
1714 
1715   fiid_obj_destroy (obj_cmd_rq);
1716   obj_cmd_rq = NULL;
1717   fiid_obj_destroy (obj_cmd_rs);
1718   obj_cmd_rs = NULL;
1719 
1720   if (!(obj_cmd_rq = fiid_obj_create (tmpl_cmd_get_session_challenge_rq)))
1721     {
1722       API_ERRNO_TO_API_ERRNUM (ctx, errno);
1723       goto cleanup;
1724     }
1725   if (!(obj_cmd_rs = fiid_obj_create (tmpl_cmd_get_session_challenge_rs)))
1726     {
1727       API_ERRNO_TO_API_ERRNUM (ctx, errno);
1728       goto cleanup;
1729     }
1730 
1731   if (fill_cmd_get_session_challenge (ctx->io.outofband.authentication_type,
1732                                       ctx->io.outofband.username,
1733                                       IPMI_MAX_USER_NAME_LENGTH,
1734                                       obj_cmd_rq) < 0)
1735     {
1736       API_ERRNO_TO_API_ERRNUM (ctx, errno);
1737       goto cleanup;
1738     }
1739 
1740   if (api_lan_cmd_wrapper (ctx,
1741                            IPMI_INTERNAL_WORKAROUND_FLAGS_GET_SESSION_CHALLENGE,
1742                            IPMI_BMC_IPMB_LUN_BMC,
1743                            IPMI_NET_FN_APP_RQ,
1744                            IPMI_AUTHENTICATION_TYPE_NONE,
1745                            0,
1746                            NULL,
1747                            0,
1748                            &(ctx->io.outofband.rq_seq),
1749                            NULL,
1750                            0,
1751                            obj_cmd_rq,
1752                            obj_cmd_rs) < 0)
1753     goto cleanup;
1754 
1755   if ((ret = ipmi_check_completion_code_success (obj_cmd_rs)) < 0)
1756     {
1757       API_ERRNO_TO_API_ERRNUM (ctx, errno);
1758       goto cleanup;
1759     }
1760 
1761   if (!ret)
1762     {
1763       if (ipmi_check_completion_code (obj_cmd_rs, IPMI_COMP_CODE_GET_SESSION_CHALLENGE_INVALID_USERNAME) == 1
1764           || ipmi_check_completion_code (obj_cmd_rs, IPMI_COMP_CODE_GET_SESSION_CHALLENGE_NULL_USERNAME_NOT_ENABLED) == 1)
1765         API_SET_ERRNUM (ctx, IPMI_ERR_USERNAME_INVALID);
1766       else
1767         API_BAD_RESPONSE_TO_API_ERRNUM (ctx, obj_cmd_rs);
1768       goto cleanup;
1769     }
1770 
1771   if (FIID_OBJ_GET (obj_cmd_rs,
1772                     "temp_session_id",
1773                     &val) < 0)
1774     {
1775       API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_cmd_rs);
1776       goto cleanup;
1777     }
1778   temp_session_id = val;
1779 
1780   if ((challenge_string_len = fiid_obj_get_data (obj_cmd_rs,
1781                                                  "challenge_string",
1782                                                  challenge_string,
1783                                                  IPMI_CHALLENGE_STRING_LENGTH)) < 0)
1784     {
1785       API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_cmd_rs);
1786       goto cleanup;
1787     }
1788 
1789   fiid_obj_destroy (obj_cmd_rq);
1790   obj_cmd_rq = NULL;
1791   fiid_obj_destroy (obj_cmd_rs);
1792   obj_cmd_rs = NULL;
1793 
1794   if (!(obj_cmd_rq = fiid_obj_create (tmpl_cmd_activate_session_rq)))
1795     {
1796       API_ERRNO_TO_API_ERRNUM (ctx, errno);
1797       goto cleanup;
1798     }
1799   if (!(obj_cmd_rs = fiid_obj_create (tmpl_cmd_activate_session_rs)))
1800     {
1801       API_ERRNO_TO_API_ERRNUM (ctx, errno);
1802       goto cleanup;
1803     }
1804 
1805   initial_outbound_sequence_number = rand ();
1806 
1807   if (fill_cmd_activate_session (ctx->io.outofband.authentication_type,
1808                                  ctx->io.outofband.privilege_level,
1809                                  challenge_string,
1810                                  challenge_string_len,
1811                                  initial_outbound_sequence_number,
1812                                  obj_cmd_rq) < 0)
1813     {
1814       API_ERRNO_TO_API_ERRNUM (ctx, errno);
1815       goto cleanup;
1816     }
1817 
1818   if (api_lan_cmd_wrapper (ctx,
1819                            0,
1820                            IPMI_BMC_IPMB_LUN_BMC,
1821                            IPMI_NET_FN_APP_RQ,
1822                            ctx->io.outofband.authentication_type,
1823                            1,
1824                            NULL,
1825                            temp_session_id,
1826                            &(ctx->io.outofband.rq_seq),
1827                            ctx->io.outofband.password,
1828                            IPMI_1_5_MAX_PASSWORD_LENGTH,
1829                            obj_cmd_rq,
1830                            obj_cmd_rs) < 0)
1831     {
1832       if (ctx->errnum == IPMI_ERR_SESSION_TIMEOUT)
1833         API_SET_ERRNUM (ctx, IPMI_ERR_PASSWORD_VERIFICATION_TIMEOUT);
1834       goto cleanup;
1835     }
1836 
1837   if ((ret = ipmi_check_completion_code_success (obj_cmd_rs)) < 0)
1838     {
1839       API_ERRNO_TO_API_ERRNUM (ctx, errno);
1840       goto cleanup;
1841     }
1842 
1843   if (!ret)
1844     {
1845       if (ipmi_check_completion_code (obj_cmd_rs, IPMI_COMP_CODE_ACTIVATE_SESSION_NO_SESSION_SLOT_AVAILABLE) == 1
1846           || ipmi_check_completion_code (obj_cmd_rs, IPMI_COMP_CODE_ACTIVATE_SESSION_NO_SLOT_AVAILABLE_FOR_GIVEN_USER) == 1
1847           || ipmi_check_completion_code (obj_cmd_rs, IPMI_COMP_CODE_ACTIVATE_SESSION_NO_SLOT_AVAILABLE_TO_SUPPORT_USER) == 1)
1848         API_SET_ERRNUM (ctx, IPMI_ERR_BMC_BUSY);
1849       else if (ipmi_check_completion_code (obj_cmd_rs, IPMI_COMP_CODE_ACTIVATE_SESSION_EXCEEDS_PRIVILEGE_LEVEL) == 1)
1850         API_SET_ERRNUM (ctx, IPMI_ERR_PRIVILEGE_LEVEL_CANNOT_BE_OBTAINED);
1851 #if 0
1852       /* achu: noticed this on an Inventec 5441/Dell Xanadu II under
1853        * some scenarios.  Password Invalid doesn't seem right, b/c on
1854        * other motherboards it may be a legitimate bad input.  I think
1855        * it best to comment this out and let the vendor fix their
1856        * firmware.
1857        */
1858        else if (ipmi_check_completion_code (obj_cmd_rs, IPMI_COMP_CODE_INVALID_DATA_FIELD_IN_REQUEST) == 1)
1859         API_SET_ERRNUM (ctx, IPMI_ERR_PASSWORD_INVALID);
1860 #endif
1861       /*
1862        * IPMI Workaround
1863        *
1864        * Discovered on Xyratex HB-F8-SRAY
1865        *
1866        * For some reason on this system, if you do not specify a
1867        * privilege level of Admin, this completion code will always be
1868        * returned.  Reason unknown.  This isn't the best/right error
1869        * to return, but it will atleast point the user to a way to
1870        * work around the problem.
1871        */
1872        else if (ipmi_check_completion_code (obj_cmd_rs, IPMI_COMP_CODE_INSUFFICIENT_PRIVILEGE_LEVEL) == 1)
1873          API_SET_ERRNUM (ctx, IPMI_ERR_PRIVILEGE_LEVEL_CANNOT_BE_OBTAINED);
1874       else
1875         API_BAD_RESPONSE_TO_API_ERRNUM (ctx, obj_cmd_rs);
1876       goto cleanup;
1877     }
1878 
1879   if (FIID_OBJ_GET (obj_cmd_rs,
1880                     "session_id",
1881                     &val) < 0)
1882     {
1883       API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_cmd_rs);
1884       goto cleanup;
1885     }
1886   ctx->io.outofband.session_id = val;
1887 
1888   /* achu: On some buggy BMCs the initial outbound sequence number on
1889    * the activate session response is off by one.  So we just accept
1890    * whatever sequence number they give us even if it isn't the
1891    * initial outbound sequence number.
1892    */
1893   if (FIID_OBJ_GET (ctx->io.outofband.rs.obj_lan_session_hdr,
1894                     "session_sequence_number",
1895                     &val) < 0)
1896     {
1897       API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, ctx->io.outofband.rs.obj_lan_session_hdr);
1898       goto cleanup;
1899     }
1900   ctx->io.outofband.highest_received_sequence_number = val;
1901 
1902   /* IPMI Workaround (achu)
1903    *
1904    * Discovered on Sun Fire 4100.
1905    *
1906    * The session sequence numbers for IPMI 1.5 are the wrong endian.
1907    * So we have to flip the bits to workaround it.
1908    */
1909   if (ctx->workaround_flags_outofband & IPMI_WORKAROUND_FLAGS_OUTOFBAND_BIG_ENDIAN_SEQUENCE_NUMBER)
1910     {
1911       uint32_t tmp_session_sequence_number = ctx->io.outofband.highest_received_sequence_number;
1912 
1913       ctx->io.outofband.highest_received_sequence_number =
1914         ((tmp_session_sequence_number & 0xFF000000) >> 24)
1915         | ((tmp_session_sequence_number & 0x00FF0000) >> 8)
1916         | ((tmp_session_sequence_number & 0x0000FF00) << 8)
1917         | ((tmp_session_sequence_number & 0x000000FF) << 24);
1918     }
1919 
1920   if (FIID_OBJ_GET (obj_cmd_rs,
1921                     "initial_inbound_sequence_number",
1922                     &val) < 0)
1923     {
1924       API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_cmd_rs);
1925       goto cleanup;
1926     }
1927   ctx->io.outofband.session_sequence_number = val;
1928 
1929   if (FIID_OBJ_GET (obj_cmd_rs,
1930                     "authentication_type",
1931                     &val) < 0)
1932     {
1933       API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_cmd_rs);
1934       goto cleanup;
1935     }
1936   authentication_type = val;
1937 
1938   /* IPMI Workaround (achu)
1939    *
1940    * Discovered on Supermicro H8QME with SIMSO daughter card.
1941    *
1942    * (Note: This could work for "IBM eServer 325" per msg auth
1943    * problem.  But I don't have hardware to test it :-()
1944    *
1945    * The remote BMC ignores if permsg authentiction is disabled.
1946    * Handle it appropriately by just not doing permsg authentication.
1947    */
1948   if (ctx->io.outofband.per_msg_auth_disabled
1949       && authentication_type != IPMI_AUTHENTICATION_TYPE_NONE)
1950     ctx->io.outofband.per_msg_auth_disabled = 0;
1951 
1952   fiid_obj_destroy (obj_cmd_rq);
1953   obj_cmd_rq = NULL;
1954   fiid_obj_destroy (obj_cmd_rs);
1955   obj_cmd_rs = NULL;
1956 
1957   /* if privilege_level == IPMI_PRIVILEGE_LEVEL_USER we shouldn't have
1958    * to call this, b/c it should be USER by default.  But I don't
1959    * trust IPMI implementations.  Do it anyways.
1960    */
1961 
1962   /* achu: At this point in time, the session is actually setup
1963    * legitimately, so we can use the actual set session privilege
1964    * level API function.
1965    */
1966   if (!(obj_cmd_rs = fiid_obj_create (tmpl_cmd_set_session_privilege_level_rs)))
1967     {
1968       API_ERRNO_TO_API_ERRNUM (ctx, errno);
1969       goto cleanup;
1970     }
1971 
1972   if (ipmi_cmd_set_session_privilege_level (ctx,
1973                                             ctx->io.outofband.privilege_level,
1974                                             obj_cmd_rs) < 0)
1975     {
1976       if (ctx->errnum == IPMI_ERR_BAD_COMPLETION_CODE)
1977         {
1978           if (ipmi_check_completion_code (obj_cmd_rs, IPMI_COMP_CODE_SET_SESSION_PRIVILEGE_LEVEL_REQUESTED_LEVEL_NOT_AVAILABLE_FOR_USER) == 1
1979               || ipmi_check_completion_code (obj_cmd_rs, IPMI_COMP_CODE_SET_SESSION_PRIVILEGE_LEVEL_REQUESTED_LEVEL_EXCEEDS_USER_PRIVILEGE_LIMIT) == 1)
1980             API_SET_ERRNUM (ctx, IPMI_ERR_PRIVILEGE_LEVEL_CANNOT_BE_OBTAINED);
1981         }
1982       ERR_TRACE (ipmi_ctx_strerror (ctx->errnum), ctx->errnum);
1983       goto cleanup;
1984     }
1985 
1986  out:
1987   rv = 0;
1988  cleanup:
1989   fiid_obj_destroy (obj_cmd_rq);
1990   fiid_obj_destroy (obj_cmd_rs);
1991   return (rv);
1992 }
1993 
1994 int
api_lan_close_session(ipmi_ctx_t ctx)1995 api_lan_close_session (ipmi_ctx_t ctx)
1996 {
1997   fiid_obj_t obj_cmd_rq = NULL;
1998   fiid_obj_t obj_cmd_rs = NULL;
1999   uint8_t authentication_type;
2000   unsigned int internal_workaround_flags = 0;
2001   int ret, rv = -1;
2002 
2003   /* Do not use ipmi_cmd_close_session(), we use a close session retransmit workaround */
2004 
2005   assert (ctx
2006           && ctx->magic == IPMI_CTX_MAGIC
2007           && ctx->type == IPMI_DEVICE_LAN
2008           && ctx->io.outofband.sockfd);
2009 
2010   if (!(obj_cmd_rq = fiid_obj_create (tmpl_cmd_close_session_rq)))
2011     {
2012       API_ERRNO_TO_API_ERRNUM (ctx, errno);
2013       return (-1);
2014     }
2015 
2016   if (!(obj_cmd_rs = fiid_obj_create (tmpl_cmd_close_session_rs)))
2017     {
2018       API_ERRNO_TO_API_ERRNUM (ctx, errno);
2019       return (-1);
2020     }
2021 
2022   if (fill_cmd_close_session (ctx->io.outofband.session_id,
2023                               NULL,
2024                               obj_cmd_rq) < 0)
2025     {
2026       API_ERRNO_TO_API_ERRNUM (ctx, errno);
2027       goto cleanup;
2028     }
2029 
2030   api_lan_cmd_get_session_parameters (ctx,
2031                                       &authentication_type,
2032                                       &internal_workaround_flags);
2033 
2034   internal_workaround_flags |= IPMI_INTERNAL_WORKAROUND_FLAGS_CLOSE_SESSION_SKIP_RETRANSMIT;
2035   if (api_lan_cmd_wrapper (ctx,
2036                            internal_workaround_flags,
2037                            IPMI_BMC_IPMB_LUN_BMC,
2038                            IPMI_NET_FN_APP_RQ,
2039                            authentication_type,
2040                            1,
2041                            &(ctx->io.outofband.session_sequence_number),
2042                            ctx->io.outofband.session_id,
2043                            &(ctx->io.outofband.rq_seq),
2044                            ctx->io.outofband.password,
2045                            IPMI_1_5_MAX_PASSWORD_LENGTH,
2046                            obj_cmd_rq,
2047                            obj_cmd_rs) < 0)
2048     goto cleanup;
2049 
2050   /* Check completion code just for tracing, but don't return error */
2051 
2052   if ((ret = ipmi_check_completion_code_success (obj_cmd_rs)) < 0)
2053     {
2054       API_ERRNO_TO_API_ERRNUM (ctx, errno);
2055       goto out;
2056     }
2057 
2058   if (!ret)
2059     {
2060       API_BAD_RESPONSE_TO_API_ERRNUM (ctx, obj_cmd_rs);
2061       goto out;
2062     }
2063 
2064  out:
2065   rv = 0;
2066  cleanup:
2067   fiid_obj_destroy (obj_cmd_rq);
2068   fiid_obj_destroy (obj_cmd_rs);
2069   return (rv);
2070 }
2071 
2072 static void
_api_lan_2_0_dump_rq(ipmi_ctx_t ctx,uint8_t authentication_algorithm,uint8_t integrity_algorithm,uint8_t confidentiality_algorithm,const void * integrity_key,unsigned int integrity_key_len,const void * confidentiality_key,unsigned int confidentiality_key_len,const void * pkt,unsigned int pkt_len,uint8_t cmd,uint8_t net_fn,uint8_t group_extension,fiid_obj_t obj_cmd_rq)2073 _api_lan_2_0_dump_rq (ipmi_ctx_t ctx,
2074                       uint8_t authentication_algorithm,
2075                       uint8_t integrity_algorithm,
2076                       uint8_t confidentiality_algorithm,
2077                       const void *integrity_key,
2078                       unsigned int integrity_key_len,
2079                       const void *confidentiality_key,
2080                       unsigned int confidentiality_key_len,
2081                       const void *pkt,
2082                       unsigned int pkt_len,
2083                       uint8_t cmd,
2084                       uint8_t net_fn,
2085                       uint8_t group_extension,
2086                       fiid_obj_t obj_cmd_rq)
2087 {
2088   fiid_field_t *tmpl_cmd = NULL;
2089 
2090   assert (ctx
2091           && ctx->magic == IPMI_CTX_MAGIC
2092           && (ctx->flags & IPMI_FLAGS_DEBUG_DUMP)
2093           && IPMI_AUTHENTICATION_ALGORITHM_SUPPORTED (authentication_algorithm)
2094           && IPMI_INTEGRITY_ALGORITHM_SUPPORTED (integrity_algorithm)
2095           && IPMI_CONFIDENTIALITY_ALGORITHM_SUPPORTED (confidentiality_algorithm)
2096           && pkt
2097           && pkt_len
2098           && fiid_obj_valid (obj_cmd_rq));
2099 
2100   /* Don't cleanup/return an error here.  It's just debug code. */
2101 
2102   if ((tmpl_cmd = fiid_obj_template (obj_cmd_rq)))
2103     {
2104       char hdrbuf[DEBUG_UTIL_HDR_BUFLEN + 1];
2105       const char *cmd_str = NULL;
2106 
2107       /* Handle a few IPMI 2.0 special cases */
2108       if (fiid_template_compare (tmpl_cmd, tmpl_rmcpplus_open_session_request) == 1)
2109         cmd_str = DEBUG_UTIL_OPEN_SESSION_STR;
2110       else if (fiid_template_compare (tmpl_cmd, tmpl_rmcpplus_rakp_message_1) == 1)
2111         cmd_str = DEBUG_UTIL_RAKP_1_STR;
2112       else if (fiid_template_compare (tmpl_cmd, tmpl_rmcpplus_rakp_message_3) == 1)
2113         cmd_str = DEBUG_UTIL_RAKP_3_STR;
2114 
2115       memset (hdrbuf, '\0', DEBUG_UTIL_HDR_BUFLEN + 1);
2116 
2117       if (cmd_str)
2118         debug_hdr_str (DEBUG_UTIL_TYPE_IPMI_2_0,
2119                        DEBUG_UTIL_DIRECTION_REQUEST,
2120                        DEBUG_UTIL_FLAGS_DEFAULT,
2121                        cmd_str,
2122                        hdrbuf,
2123                        DEBUG_UTIL_HDR_BUFLEN);
2124       else
2125         debug_hdr_cmd (DEBUG_UTIL_TYPE_IPMI_2_0,
2126                        DEBUG_UTIL_DIRECTION_REQUEST,
2127                        net_fn,
2128                        cmd,
2129                        group_extension,
2130                        hdrbuf,
2131                        DEBUG_UTIL_HDR_BUFLEN);
2132 
2133       if (ctx->tmpl_ipmb_cmd_rq)
2134         ipmi_dump_rmcpplus_packet_ipmb (STDERR_FILENO,
2135                                         ctx->io.outofband.hostname,
2136                                         hdrbuf,
2137                                         NULL,
2138                                         authentication_algorithm,
2139                                         integrity_algorithm,
2140                                         confidentiality_algorithm,
2141                                         integrity_key,
2142                                         integrity_key_len,
2143                                         confidentiality_key,
2144                                         confidentiality_key_len,
2145                                         pkt,
2146                                         pkt_len,
2147                                         tmpl_lan_msg_hdr_rs,
2148                                         tmpl_cmd,
2149                                         tmpl_ipmb_msg_hdr_rq,
2150                                         ctx->tmpl_ipmb_cmd_rq);
2151       else
2152         ipmi_dump_rmcpplus_packet (STDERR_FILENO,
2153                                    ctx->io.outofband.hostname,
2154                                    hdrbuf,
2155                                    NULL,
2156                                    authentication_algorithm,
2157                                    integrity_algorithm,
2158                                    confidentiality_algorithm,
2159                                    integrity_key,
2160                                    integrity_key_len,
2161                                    confidentiality_key,
2162                                    confidentiality_key_len,
2163                                    pkt,
2164                                    pkt_len,
2165                                    tmpl_lan_msg_hdr_rq,
2166                                    tmpl_cmd);
2167 
2168       fiid_template_free (tmpl_cmd);
2169     }
2170 }
2171 
2172 static void
_api_lan_2_0_dump_rs(ipmi_ctx_t ctx,uint8_t authentication_algorithm,uint8_t integrity_algorithm,uint8_t confidentiality_algorithm,const void * integrity_key,unsigned int integrity_key_len,const void * confidentiality_key,unsigned int confidentiality_key_len,const void * pkt,unsigned int pkt_len,uint8_t cmd,uint8_t net_fn,uint8_t group_extension,fiid_obj_t obj_cmd_rs)2173 _api_lan_2_0_dump_rs (ipmi_ctx_t ctx,
2174                       uint8_t authentication_algorithm,
2175                       uint8_t integrity_algorithm,
2176                       uint8_t confidentiality_algorithm,
2177                       const void *integrity_key,
2178                       unsigned int integrity_key_len,
2179                       const void *confidentiality_key,
2180                       unsigned int confidentiality_key_len,
2181                       const void *pkt,
2182                       unsigned int pkt_len,
2183                       uint8_t cmd,
2184                       uint8_t net_fn,
2185                       uint8_t group_extension,
2186                       fiid_obj_t obj_cmd_rs)
2187 {
2188   fiid_field_t *tmpl_cmd = NULL;
2189 
2190   assert (ctx
2191           && ctx->magic == IPMI_CTX_MAGIC
2192           && (ctx->flags & IPMI_FLAGS_DEBUG_DUMP)
2193           && IPMI_AUTHENTICATION_ALGORITHM_SUPPORTED (authentication_algorithm)
2194           && IPMI_INTEGRITY_ALGORITHM_SUPPORTED (integrity_algorithm)
2195           && IPMI_CONFIDENTIALITY_ALGORITHM_SUPPORTED (confidentiality_algorithm)
2196           && pkt
2197           && pkt_len
2198           && fiid_obj_valid (obj_cmd_rs));
2199 
2200   /* Don't cleanup/return an error here.  It's just debug code. */
2201 
2202   if ((tmpl_cmd = fiid_obj_template (obj_cmd_rs)))
2203     {
2204       char hdrbuf[DEBUG_UTIL_HDR_BUFLEN + 1];
2205       const char *cmd_str = NULL;
2206 
2207       /* Handle a few IPMI 2.0 special cases */
2208       if (fiid_template_compare (tmpl_cmd, tmpl_rmcpplus_open_session_response) == 1)
2209         cmd_str = DEBUG_UTIL_OPEN_SESSION_STR;
2210       else if (fiid_template_compare (tmpl_cmd, tmpl_rmcpplus_rakp_message_2) == 1)
2211         cmd_str = DEBUG_UTIL_RAKP_2_STR;
2212       else if (fiid_template_compare (tmpl_cmd, tmpl_rmcpplus_rakp_message_4) == 1)
2213         cmd_str = DEBUG_UTIL_RAKP_4_STR;
2214 
2215       memset (hdrbuf, '\0', DEBUG_UTIL_HDR_BUFLEN + 1);
2216 
2217       if (cmd_str)
2218         debug_hdr_str (DEBUG_UTIL_TYPE_IPMI_2_0,
2219                        DEBUG_UTIL_DIRECTION_RESPONSE,
2220                        DEBUG_UTIL_FLAGS_DEFAULT,
2221                        cmd_str,
2222                        hdrbuf,
2223                        DEBUG_UTIL_HDR_BUFLEN);
2224       else
2225         debug_hdr_cmd (DEBUG_UTIL_TYPE_IPMI_2_0,
2226                        DEBUG_UTIL_DIRECTION_RESPONSE,
2227                        net_fn,
2228                        cmd,
2229                        group_extension,
2230                        hdrbuf,
2231                        DEBUG_UTIL_HDR_BUFLEN);
2232 
2233       ipmi_dump_rmcpplus_packet (STDERR_FILENO,
2234                                  ctx->io.outofband.hostname,
2235                                  hdrbuf,
2236                                  NULL,
2237                                  authentication_algorithm,
2238                                  integrity_algorithm,
2239                                  confidentiality_algorithm,
2240                                  integrity_key,
2241                                  integrity_key_len,
2242                                  confidentiality_key,
2243                                  confidentiality_key_len,
2244                                  pkt,
2245                                  pkt_len,
2246                                  tmpl_lan_msg_hdr_rs,
2247                                  tmpl_cmd);
2248 
2249       fiid_template_free (tmpl_cmd);
2250     }
2251 }
2252 
2253 static int
_api_lan_2_0_cmd_send(ipmi_ctx_t ctx,uint8_t lun,uint8_t net_fn,uint8_t payload_type,uint8_t payload_authenticated,uint8_t payload_encrypted,uint32_t session_sequence_number,uint32_t session_id,uint8_t rq_seq,uint8_t authentication_algorithm,uint8_t integrity_algorithm,uint8_t confidentiality_algorithm,const void * integrity_key,unsigned int integrity_key_len,const void * confidentiality_key,unsigned int confidentiality_key_len,const char * password,unsigned int password_len,uint8_t cmd,uint8_t group_extension,fiid_obj_t obj_cmd_rq)2254 _api_lan_2_0_cmd_send (ipmi_ctx_t ctx,
2255                        uint8_t lun,
2256                        uint8_t net_fn,
2257                        uint8_t payload_type,
2258                        uint8_t payload_authenticated,
2259                        uint8_t payload_encrypted,
2260                        uint32_t session_sequence_number,
2261                        uint32_t session_id,
2262                        uint8_t rq_seq,
2263                        uint8_t authentication_algorithm,
2264                        uint8_t integrity_algorithm,
2265                        uint8_t confidentiality_algorithm,
2266                        const void *integrity_key,
2267                        unsigned int integrity_key_len,
2268                        const void *confidentiality_key,
2269                        unsigned int confidentiality_key_len,
2270                        const char *password,
2271                        unsigned int password_len,
2272                        uint8_t cmd, /* for debug dumping */
2273                        uint8_t group_extension, /* for debug dumping */
2274                        fiid_obj_t obj_cmd_rq)
2275 {
2276   uint8_t *pkt = NULL;
2277   unsigned int pkt_len = 0;
2278   int cmd_len = 0;
2279   int send_len = 0;
2280   int ret, rv = -1;
2281 
2282   assert (ctx
2283           && ctx->magic == IPMI_CTX_MAGIC
2284           && ctx->io.outofband.sockfd
2285           && IPMI_BMC_LUN_VALID (lun)
2286           && IPMI_NET_FN_VALID (net_fn)
2287           && (payload_type == IPMI_PAYLOAD_TYPE_IPMI
2288               || payload_type == IPMI_PAYLOAD_TYPE_RMCPPLUS_OPEN_SESSION_REQUEST
2289               || payload_type == IPMI_PAYLOAD_TYPE_RAKP_MESSAGE_1
2290               || payload_type == IPMI_PAYLOAD_TYPE_RAKP_MESSAGE_3)
2291           && IPMI_PAYLOAD_AUTHENTICATED_FLAG_VALID (payload_authenticated)
2292           && IPMI_PAYLOAD_ENCRYPTED_FLAG_VALID (payload_encrypted)
2293           && IPMI_AUTHENTICATION_ALGORITHM_SUPPORTED (authentication_algorithm)
2294           && IPMI_INTEGRITY_ALGORITHM_SUPPORTED (integrity_algorithm)
2295           && IPMI_CONFIDENTIALITY_ALGORITHM_SUPPORTED (confidentiality_algorithm)
2296           && !(password && password_len > IPMI_2_0_MAX_PASSWORD_LENGTH)
2297           && fiid_obj_valid (obj_cmd_rq)
2298           && fiid_obj_packet_valid (obj_cmd_rq) == 1);
2299 
2300   if ((cmd_len = fiid_obj_len_bytes (obj_cmd_rq)) < 0)
2301     {
2302       API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_cmd_rq);
2303       goto cleanup;
2304     }
2305 
2306   /* variable based on authentication, etc. 1024 extra is enough */
2307   pkt_len = cmd_len + IPMI_PKT_PAD;
2308 
2309   if (!(pkt = malloc (pkt_len)))
2310     {
2311       API_ERRNO_TO_API_ERRNUM (ctx, errno);
2312       goto cleanup;
2313     }
2314 
2315   if (fill_rmcp_hdr_ipmi (ctx->io.outofband.rq.obj_rmcp_hdr) < 0)
2316     {
2317       API_ERRNO_TO_API_ERRNUM (ctx, errno);
2318       goto cleanup;
2319     }
2320 
2321   if (fill_rmcpplus_session_hdr (payload_type,
2322                                  payload_authenticated,
2323                                  payload_encrypted,
2324                                  0, /* oem_iana */
2325                                  0, /* oem_payload_id */
2326                                  session_id,
2327                                  session_sequence_number,
2328                                  ctx->io.outofband.rq.obj_rmcpplus_session_hdr) < 0)
2329     {
2330       API_ERRNO_TO_API_ERRNUM (ctx, errno);
2331       goto cleanup;
2332     }
2333 
2334   if (fill_lan_msg_hdr (IPMI_SLAVE_ADDRESS_BMC,
2335                         net_fn,
2336                         lun,
2337                         rq_seq,
2338                         ctx->io.outofband.rq.obj_lan_msg_hdr) < 0)
2339     {
2340       API_ERRNO_TO_API_ERRNUM (ctx, errno);
2341       goto cleanup;
2342     }
2343 
2344   if (fill_rmcpplus_session_trlr (ctx->io.outofband.rq.obj_rmcpplus_session_trlr) < 0)
2345     {
2346       API_ERRNO_TO_API_ERRNUM (ctx, errno);
2347       goto cleanup;
2348     }
2349 
2350   if ((send_len = assemble_ipmi_rmcpplus_pkt (authentication_algorithm,
2351                                               integrity_algorithm,
2352                                               confidentiality_algorithm,
2353                                               integrity_key,
2354                                               integrity_key_len,
2355                                               confidentiality_key,
2356                                               confidentiality_key_len,
2357                                               password,
2358                                               password_len,
2359                                               ctx->io.outofband.rq.obj_rmcp_hdr,
2360                                               ctx->io.outofband.rq.obj_rmcpplus_session_hdr,
2361                                               ctx->io.outofband.rq.obj_lan_msg_hdr,
2362                                               obj_cmd_rq,
2363                                               ctx->io.outofband.rq.obj_rmcpplus_session_trlr,
2364                                               pkt,
2365                                               pkt_len,
2366                                               IPMI_INTERFACE_FLAGS_DEFAULT)) < 0)
2367     {
2368       API_ERRNO_TO_API_ERRNUM (ctx, errno);
2369       goto cleanup;
2370     }
2371 
2372   if (ctx->flags & IPMI_FLAGS_DEBUG_DUMP && send_len)
2373     _api_lan_2_0_dump_rq (ctx,
2374                           authentication_algorithm,
2375                           integrity_algorithm,
2376                           confidentiality_algorithm,
2377                           integrity_key,
2378                           integrity_key_len,
2379                           confidentiality_key,
2380                           confidentiality_key_len,
2381                           pkt,
2382                           send_len,
2383                           cmd,
2384                           net_fn,
2385                           group_extension,
2386                           obj_cmd_rq);
2387 
2388   do
2389     {
2390       ret = ipmi_rmcpplus_sendto (ctx->io.outofband.sockfd,
2391                                   pkt,
2392                                   send_len,
2393                                   0,
2394                                   ctx->io.outofband.remote_host,
2395                                   ctx->io.outofband.remote_host_len);
2396     } while (ret < 0 && errno == EINTR);
2397 
2398   if (ret < 0)
2399     {
2400       API_ERRNO_TO_API_ERRNUM (ctx, errno);
2401       goto cleanup;
2402     }
2403 
2404   if (gettimeofday (&ctx->io.outofband.last_send, NULL) < 0)
2405     {
2406       API_ERRNO_TO_API_ERRNUM (ctx, errno);
2407       goto cleanup;
2408     }
2409 
2410   rv = 0;
2411  cleanup:
2412   free (pkt);
2413   return (rv);
2414 }
2415 
2416 /* return receive length on success, 0 on no packet, -1 on error */
2417 static int
_api_lan_2_0_cmd_recv(ipmi_ctx_t ctx,uint8_t authentication_algorithm,uint8_t integrity_algorithm,uint8_t confidentiality_algorithm,const void * integrity_key,unsigned int integrity_key_len,const void * confidentiality_key,unsigned int confidentiality_key_len,void * pkt,unsigned int pkt_len,unsigned int retransmission_count)2418 _api_lan_2_0_cmd_recv (ipmi_ctx_t ctx,
2419                        uint8_t authentication_algorithm,
2420                        uint8_t integrity_algorithm,
2421                        uint8_t confidentiality_algorithm,
2422                        const void *integrity_key,
2423                        unsigned int integrity_key_len,
2424                        const void *confidentiality_key,
2425                        unsigned int confidentiality_key_len,
2426                        void *pkt,
2427                        unsigned int pkt_len,
2428                        unsigned int retransmission_count)
2429 {
2430   struct timeval recv_starttime;
2431   int recv_len = 0;
2432 
2433   assert (ctx
2434           && ctx->magic == IPMI_CTX_MAGIC
2435           && ctx->io.outofband.sockfd
2436           && IPMI_AUTHENTICATION_ALGORITHM_SUPPORTED (authentication_algorithm)
2437           && IPMI_INTEGRITY_ALGORITHM_SUPPORTED (integrity_algorithm)
2438           && IPMI_CONFIDENTIALITY_ALGORITHM_SUPPORTED (confidentiality_algorithm)
2439           && pkt
2440           && pkt_len);
2441 
2442   if (gettimeofday (&recv_starttime, NULL) < 0)
2443     {
2444       API_ERRNO_TO_API_ERRNUM (ctx, errno);
2445       return (-1);
2446     }
2447 
2448   recv_len = _api_lan_recvfrom (ctx,
2449                                 pkt,
2450                                 pkt_len,
2451                                 retransmission_count,
2452                                 &recv_starttime);
2453 
2454   if (!recv_len)
2455     return (0); /* resend the request */
2456 
2457   /* achu & hliebig:
2458    *
2459    * Premise from ipmitool (http://ipmitool.sourceforge.net/)
2460    *
2461    * On some OSes (it seems Unixes), the behavior is to not return
2462    * errors up to the client for UDP responses (i.e. you need to
2463    * timeout).  But on some OSes (it seems Windows), the behavior is
2464    * to return port denied errors up to the user for UDP responses.
2465    *
2466    * In addition (according to Ipmitool), a read may return
2467    * ECONNREFUSED or ECONNRESET if both the OS and BMC respond to an
2468    * IPMI request.
2469    *
2470    * If the ECONNREFUSED or ECONNRESET is from the OS, but we will get
2471    * an IPMI response later, we just do the recvfrom again to get the
2472    * packet we expect.
2473    *
2474    * If the ECONNREFUSED or ECONNRESET is from the OS but there is no
2475    * BMC, just do the recvfrom again to give us the eventually
2476    * timeout.
2477    */
2478 
2479   if (recv_len < 0
2480       && (errno == ECONNRESET
2481           || errno == ECONNREFUSED))
2482     {
2483       recv_len = _api_lan_recvfrom (ctx,
2484                                     pkt,
2485                                     pkt_len,
2486                                     retransmission_count,
2487                                     &recv_starttime);
2488 
2489       if (!recv_len)
2490         return (0); /* resend the request */
2491     }
2492 
2493   if (recv_len < 0)
2494     {
2495       API_ERRNO_TO_API_ERRNUM (ctx, errno);
2496       return (-1);
2497     }
2498 
2499   return (recv_len);
2500 }
2501 
2502 /* < 0 - error
2503  * == 1 good packet
2504  * == 0 bad packet
2505  */
2506 static int
_api_lan_2_0_cmd_wrapper_verify_packet(ipmi_ctx_t ctx,uint8_t payload_type,uint8_t * message_tag,uint32_t * session_sequence_number,uint32_t session_id,uint8_t * rq_seq,uint8_t integrity_algorithm,const void * integrity_key,unsigned int integrity_key_len,const char * password,unsigned int password_len,fiid_obj_t obj_cmd_rs,const void * pkt,unsigned int pkt_len)2507 _api_lan_2_0_cmd_wrapper_verify_packet (ipmi_ctx_t ctx,
2508                                         uint8_t payload_type,
2509                                         uint8_t *message_tag,
2510                                         uint32_t *session_sequence_number,
2511                                         uint32_t session_id,
2512                                         uint8_t *rq_seq,
2513                                         uint8_t integrity_algorithm,
2514                                         const void *integrity_key,
2515                                         unsigned int integrity_key_len,
2516                                         const char *password,
2517                                         unsigned int password_len,
2518                                         fiid_obj_t obj_cmd_rs,
2519                                         const void *pkt,
2520                                         unsigned int pkt_len)
2521 {
2522   uint8_t l_payload_type;
2523   uint32_t l_session_id;
2524   uint8_t l_message_tag;
2525   uint32_t rs_session_sequence_number;
2526   uint8_t rmcpplus_status_code;
2527   uint64_t val;
2528   int ret, rv = -1;
2529 
2530   assert (ctx
2531           && ctx->magic == IPMI_CTX_MAGIC
2532           && ctx->type == IPMI_DEVICE_LAN_2_0
2533           && ctx->io.outofband.sockfd
2534           && (payload_type == IPMI_PAYLOAD_TYPE_IPMI
2535               || payload_type == IPMI_PAYLOAD_TYPE_RMCPPLUS_OPEN_SESSION_REQUEST
2536               || payload_type == IPMI_PAYLOAD_TYPE_RAKP_MESSAGE_1
2537               || payload_type == IPMI_PAYLOAD_TYPE_RAKP_MESSAGE_3)
2538           && IPMI_INTEGRITY_ALGORITHM_SUPPORTED (integrity_algorithm)
2539           && !(password && password_len > IPMI_2_0_MAX_PASSWORD_LENGTH)
2540           && fiid_obj_valid (obj_cmd_rs)
2541           && pkt
2542           && pkt_len);
2543 
2544   if (payload_type == IPMI_PAYLOAD_TYPE_IPMI)
2545     {
2546       if (FIID_OBJ_GET (ctx->io.outofband.rs.obj_rmcpplus_session_hdr,
2547                         "payload_type",
2548                         &val) < 0)
2549         {
2550           API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, ctx->io.outofband.rs.obj_rmcpplus_session_hdr);
2551           goto cleanup;
2552         }
2553       l_payload_type = val;
2554 
2555       if (l_payload_type != IPMI_PAYLOAD_TYPE_IPMI)
2556         {
2557           rv = 0;
2558           goto cleanup;
2559         }
2560 
2561       if (FIID_OBJ_GET (ctx->io.outofband.rs.obj_rmcpplus_session_hdr,
2562                         "session_id",
2563                         &val) < 0)
2564         {
2565           API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, ctx->io.outofband.rs.obj_rmcpplus_session_hdr);
2566           goto cleanup;
2567         }
2568       l_session_id = val;
2569 
2570       if (l_session_id != ctx->io.outofband.remote_console_session_id)
2571         {
2572           rv = 0;
2573           goto cleanup;
2574         }
2575 
2576       /* IPMI Workaround (achu)
2577        *
2578        * Discovered on Supermicro X9SCM-iiF, Supermicro X9DRi-F
2579        *
2580        * Checksums are computed incorrectly.
2581        */
2582       if (!(ctx->workaround_flags_outofband_2_0 & IPMI_WORKAROUND_FLAGS_OUTOFBAND_2_0_NO_CHECKSUM_CHECK))
2583         {
2584           if ((ret = ipmi_lan_check_checksum (ctx->io.outofband.rs.obj_lan_msg_hdr,
2585                                               obj_cmd_rs,
2586                                               ctx->io.outofband.rs.obj_lan_msg_trlr)) < 0)
2587             {
2588               API_ERRNO_TO_API_ERRNUM (ctx, errno);
2589               goto cleanup;
2590             }
2591 
2592           if (!ret)
2593             {
2594               rv = 0;
2595               goto cleanup;
2596             }
2597         }
2598 
2599       if ((ret = ipmi_rmcpplus_check_packet_session_authentication_code (integrity_algorithm,
2600                                                                          pkt,
2601                                                                          pkt_len,
2602                                                                          integrity_key,
2603                                                                          integrity_key_len,
2604                                                                          password,
2605                                                                          password_len,
2606                                                                          ctx->io.outofband.rs.obj_rmcpplus_session_trlr)) < 0)
2607         {
2608           API_ERRNO_TO_API_ERRNUM (ctx, errno);
2609           goto cleanup;
2610         }
2611 
2612       if (!ret)
2613         {
2614           rv = 0;
2615           goto cleanup;
2616         }
2617 
2618       if (session_sequence_number)
2619         {
2620           if (FIID_OBJ_GET (ctx->io.outofband.rs.obj_rmcpplus_session_hdr,
2621                             "session_sequence_number",
2622                             &val) < 0)
2623             {
2624               API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, ctx->io.outofband.rs.obj_rmcpplus_session_hdr);
2625               goto cleanup;
2626             }
2627           rs_session_sequence_number = val;
2628 
2629           if ((ret = _ipmi_check_session_sequence_number (ctx,
2630                                                           rs_session_sequence_number)) < 0)
2631             {
2632               API_ERRNO_TO_API_ERRNUM (ctx, errno);
2633               goto cleanup;
2634             }
2635 
2636           if (!ret)
2637             {
2638               rv = 0;
2639               goto cleanup;
2640             }
2641         }
2642 
2643       if ((ret = ipmi_lan_check_rq_seq (ctx->io.outofband.rs.obj_lan_msg_hdr,
2644                                         (rq_seq) ? *rq_seq : 0)) < 0)
2645         {
2646           API_ERRNO_TO_API_ERRNUM (ctx, errno);
2647           goto cleanup;
2648         }
2649 
2650       if (!ret)
2651         {
2652           rv = 0;
2653           goto cleanup;
2654         }
2655     }
2656   else if (payload_type == IPMI_PAYLOAD_TYPE_RMCPPLUS_OPEN_SESSION_REQUEST)
2657     {
2658       if (FIID_OBJ_GET (ctx->io.outofband.rs.obj_rmcpplus_session_hdr,
2659                         "payload_type",
2660                         &val) < 0)
2661         {
2662           API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, ctx->io.outofband.rs.obj_rmcpplus_session_hdr);
2663           goto cleanup;
2664         }
2665       l_payload_type = val;
2666 
2667       if (l_payload_type != IPMI_PAYLOAD_TYPE_RMCPPLUS_OPEN_SESSION_RESPONSE)
2668         {
2669           rv = 0;
2670           goto cleanup;
2671         }
2672 
2673       if (message_tag)
2674         {
2675           if (FIID_OBJ_GET (obj_cmd_rs,
2676                             "message_tag",
2677                             &val) < 0)
2678             {
2679               API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_cmd_rs);
2680               goto cleanup;
2681             }
2682           l_message_tag = val;
2683 
2684           if (l_message_tag != *message_tag)
2685             {
2686               rv = 0;
2687               goto cleanup;
2688             }
2689         }
2690 
2691       /* There is no guarantee that other data (authentication keys,
2692        * session id's, etc.) in the RAKP response will be valid if
2693        * there is a status code error.  So we check this status code
2694        * along with this stuff.
2695        */
2696 
2697       if (FIID_OBJ_GET (obj_cmd_rs,
2698                         "rmcpplus_status_code",
2699                         &val) < 0)
2700         {
2701           API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_cmd_rs);
2702           goto cleanup;
2703         }
2704       rmcpplus_status_code = val;
2705 
2706       if (FIID_OBJ_GET (obj_cmd_rs,
2707                         "remote_console_session_id",
2708                         &val) < 0)
2709         {
2710           API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_cmd_rs);
2711           goto cleanup;
2712         }
2713       l_session_id = val;
2714 
2715       if (rmcpplus_status_code == RMCPPLUS_STATUS_NO_ERRORS
2716           && l_session_id != ctx->io.outofband.remote_console_session_id)
2717         {
2718           rv = 0;
2719           goto cleanup;
2720         }
2721 
2722     }
2723   else if (payload_type == IPMI_PAYLOAD_TYPE_RAKP_MESSAGE_1)
2724     {
2725       if (FIID_OBJ_GET (ctx->io.outofband.rs.obj_rmcpplus_session_hdr,
2726                         "payload_type",
2727                         &val) < 0)
2728         {
2729           API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, ctx->io.outofband.rs.obj_rmcpplus_session_hdr);
2730           goto cleanup;
2731         }
2732       l_payload_type = val;
2733 
2734       if (l_payload_type != IPMI_PAYLOAD_TYPE_RAKP_MESSAGE_2)
2735         {
2736           rv = 0;
2737           goto cleanup;
2738         }
2739 
2740       if (message_tag)
2741         {
2742           if (FIID_OBJ_GET (obj_cmd_rs,
2743                             "message_tag",
2744                             &val) < 0)
2745             {
2746               API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_cmd_rs);
2747               goto cleanup;
2748             }
2749           l_message_tag = val;
2750 
2751           if (l_message_tag != *message_tag)
2752             {
2753               rv = 0;
2754               goto cleanup;
2755             }
2756         }
2757 
2758       /* There is no guarantee that other data (authentication keys,
2759        * session id's, etc.) in the RAKP response will be valid if
2760        * there is a status code error.  So we check this status code
2761        * along with this stuff.
2762        */
2763 
2764       if (FIID_OBJ_GET (obj_cmd_rs,
2765                         "rmcpplus_status_code",
2766                         &val) < 0)
2767         {
2768           API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_cmd_rs);
2769           goto cleanup;
2770         }
2771       rmcpplus_status_code = val;
2772 
2773       if (FIID_OBJ_GET (obj_cmd_rs,
2774                         "remote_console_session_id",
2775                         &val) < 0)
2776         {
2777           API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_cmd_rs);
2778           goto cleanup;
2779         }
2780       l_session_id = val;
2781 
2782       if (rmcpplus_status_code == RMCPPLUS_STATUS_NO_ERRORS
2783           && l_session_id != ctx->io.outofband.remote_console_session_id)
2784         {
2785           rv = 0;
2786           goto cleanup;
2787         }
2788     }
2789   else if (payload_type == IPMI_PAYLOAD_TYPE_RAKP_MESSAGE_3)
2790     {
2791       if (FIID_OBJ_GET (ctx->io.outofband.rs.obj_rmcpplus_session_hdr,
2792                         "payload_type",
2793                         &val) < 0)
2794         {
2795           API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, ctx->io.outofband.rs.obj_rmcpplus_session_hdr);
2796           goto cleanup;
2797         }
2798       l_payload_type = val;
2799 
2800       if (l_payload_type != IPMI_PAYLOAD_TYPE_RAKP_MESSAGE_4)
2801         {
2802           rv = 0;
2803           goto cleanup;
2804         }
2805 
2806       if (message_tag)
2807         {
2808           if (FIID_OBJ_GET (obj_cmd_rs,
2809                             "message_tag",
2810                             &val) < 0)
2811             {
2812               API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_cmd_rs);
2813               goto cleanup;
2814             }
2815           l_message_tag = val;
2816 
2817           if (l_message_tag != *message_tag)
2818             {
2819               rv = 0;
2820               goto cleanup;
2821             }
2822         }
2823 
2824       /* There is no guarantee that other data (e.g. authentication
2825        * keys, session id's, etc.) in the RAKP response will be valid
2826        * if there is a status code error.  So we check this status
2827        * code along with this stuff.
2828        */
2829 
2830       if (FIID_OBJ_GET (obj_cmd_rs,
2831                         "rmcpplus_status_code",
2832                         &val) < 0)
2833         {
2834           API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_cmd_rs);
2835           goto cleanup;
2836         }
2837       rmcpplus_status_code = val;
2838 
2839       if (FIID_OBJ_GET (obj_cmd_rs,
2840                         "remote_console_session_id",
2841                         &val) < 0)
2842         {
2843           API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_cmd_rs);
2844           goto cleanup;
2845         }
2846       l_session_id = val;
2847 
2848       if (rmcpplus_status_code == RMCPPLUS_STATUS_NO_ERRORS
2849           && l_session_id != ctx->io.outofband.remote_console_session_id)
2850         {
2851           rv = 0;
2852           goto cleanup;
2853         }
2854     }
2855 
2856   rv = 1;
2857  cleanup:
2858   return (rv);
2859 }
2860 
2861 int
api_lan_2_0_cmd_wrapper(ipmi_ctx_t ctx,unsigned int internal_workaround_flags,uint8_t lun,uint8_t net_fn,uint8_t payload_type,uint8_t payload_authenticated,uint8_t payload_encrypted,uint8_t * message_tag,uint32_t * session_sequence_number,uint32_t session_id,uint8_t * rq_seq,uint8_t authentication_algorithm,uint8_t integrity_algorithm,uint8_t confidentiality_algorithm,const void * integrity_key,unsigned int integrity_key_len,const void * confidentiality_key,unsigned int confidentiality_key_len,const char * password,unsigned int password_len,fiid_obj_t obj_cmd_rq,fiid_obj_t obj_cmd_rs)2862 api_lan_2_0_cmd_wrapper (ipmi_ctx_t ctx,
2863                          unsigned int internal_workaround_flags,
2864                          uint8_t lun,
2865                          uint8_t net_fn,
2866                          uint8_t payload_type,
2867                          uint8_t payload_authenticated,
2868                          uint8_t payload_encrypted,
2869                          uint8_t *message_tag,
2870                          uint32_t *session_sequence_number,
2871                          uint32_t session_id,
2872                          uint8_t *rq_seq,
2873                          uint8_t authentication_algorithm,
2874                          uint8_t integrity_algorithm,
2875                          uint8_t confidentiality_algorithm,
2876                          const void *integrity_key,
2877                          unsigned int integrity_key_len,
2878                          const void *confidentiality_key,
2879                          unsigned int confidentiality_key_len,
2880                          const char *password,
2881                          unsigned int password_len,
2882                          fiid_obj_t obj_cmd_rq,
2883                          fiid_obj_t obj_cmd_rs)
2884 {
2885   int recv_len, ret, rv = -1;
2886   unsigned int retransmission_count = 0;
2887   uint8_t pkt[IPMI_MAX_PKT_LEN];
2888   uint8_t cmd = 0;             /* used for debugging */
2889   uint8_t group_extension = 0; /* used for debugging */
2890   uint64_t val;
2891   unsigned int intf_flags = IPMI_INTERFACE_FLAGS_DEFAULT;
2892 
2893   assert (ctx
2894           && ctx->magic == IPMI_CTX_MAGIC
2895           && ctx->type == IPMI_DEVICE_LAN_2_0
2896           && ctx->io.outofband.sockfd
2897           && IPMI_BMC_LUN_VALID (lun)
2898           && IPMI_NET_FN_VALID (net_fn)
2899           && (payload_type == IPMI_PAYLOAD_TYPE_IPMI
2900               || payload_type == IPMI_PAYLOAD_TYPE_RMCPPLUS_OPEN_SESSION_REQUEST
2901               || payload_type == IPMI_PAYLOAD_TYPE_RAKP_MESSAGE_1
2902               || payload_type == IPMI_PAYLOAD_TYPE_RAKP_MESSAGE_3)
2903           && IPMI_PAYLOAD_AUTHENTICATED_FLAG_VALID (payload_authenticated)
2904           && IPMI_PAYLOAD_ENCRYPTED_FLAG_VALID (payload_encrypted)
2905           && (!message_tag
2906               || (payload_type == IPMI_PAYLOAD_TYPE_RMCPPLUS_OPEN_SESSION_REQUEST
2907                   || payload_type == IPMI_PAYLOAD_TYPE_RAKP_MESSAGE_1
2908                   || payload_type == IPMI_PAYLOAD_TYPE_RAKP_MESSAGE_3))
2909           && IPMI_AUTHENTICATION_ALGORITHM_SUPPORTED (authentication_algorithm)
2910           && IPMI_INTEGRITY_ALGORITHM_SUPPORTED (integrity_algorithm)
2911           && IPMI_CONFIDENTIALITY_ALGORITHM_SUPPORTED (confidentiality_algorithm)
2912           && !(password && password_len > IPMI_2_0_MAX_PASSWORD_LENGTH)
2913           && fiid_obj_valid (obj_cmd_rq)
2914           && fiid_obj_packet_valid (obj_cmd_rq) == 1
2915           && fiid_obj_valid (obj_cmd_rs));
2916 
2917   if (ctx->flags & IPMI_FLAGS_NO_LEGAL_CHECK)
2918     intf_flags |= IPMI_INTERFACE_FLAGS_NO_LEGAL_CHECK;
2919 
2920   if (!ctx->io.outofband.last_received.tv_sec
2921       && !ctx->io.outofband.last_received.tv_usec)
2922     {
2923       if (gettimeofday (&ctx->io.outofband.last_received, NULL) < 0)
2924         {
2925           API_ERRNO_TO_API_ERRNUM (ctx, errno);
2926           return (-1);
2927         }
2928     }
2929 
2930   if (ctx->flags & IPMI_FLAGS_DEBUG_DUMP)
2931     {
2932       /* ignore error, continue on */
2933       if (FIID_OBJ_GET (obj_cmd_rq,
2934                         "cmd",
2935                         &val) < 0)
2936         API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_cmd_rq);
2937       else
2938         cmd = val;
2939 
2940       if (IPMI_NET_FN_GROUP_EXTENSION (net_fn))
2941         {
2942           /* ignore error, continue on */
2943           if (FIID_OBJ_GET (obj_cmd_rq,
2944                             "group_extension_identification",
2945                             &val) < 0)
2946             API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_cmd_rq);
2947           else
2948             group_extension = val;
2949         }
2950     }
2951 
2952   if (_api_lan_2_0_cmd_send (ctx,
2953                              lun,
2954                              net_fn,
2955                              payload_type,
2956                              payload_authenticated,
2957                              payload_encrypted,
2958                              (session_sequence_number) ? *session_sequence_number : 0,
2959                              session_id,
2960                              (rq_seq) ? *rq_seq : 0,
2961                              authentication_algorithm,
2962                              integrity_algorithm,
2963                              confidentiality_algorithm,
2964                              integrity_key,
2965                              integrity_key_len,
2966                              confidentiality_key,
2967                              confidentiality_key_len,
2968                              password,
2969                              password_len,
2970                              cmd, /* for debug dumping */
2971                              group_extension, /* for debug dumping */
2972                              obj_cmd_rq) < 0)
2973     goto cleanup;
2974 
2975   while (1)
2976     {
2977       if ((ret = _session_timed_out (ctx)) < 0)
2978         break;
2979 
2980       if (ret)
2981         {
2982           API_SET_ERRNUM (ctx, IPMI_ERR_SESSION_TIMEOUT);
2983           break;
2984         }
2985 
2986       /* its ok to use the "request" net_fn, dump code doesn't care */
2987       if ((recv_len = _api_lan_2_0_cmd_recv (ctx,
2988                                              authentication_algorithm,
2989                                              integrity_algorithm,
2990                                              confidentiality_algorithm,
2991                                              integrity_key,
2992                                              integrity_key_len,
2993                                              confidentiality_key,
2994                                              confidentiality_key_len,
2995                                              pkt,
2996                                              IPMI_MAX_PKT_LEN,
2997                                              retransmission_count)) < 0)
2998         break;
2999 
3000       if (!recv_len)
3001         {
3002           /* ignore timeout, just cleanly close session */
3003           if (internal_workaround_flags & IPMI_INTERNAL_WORKAROUND_FLAGS_CLOSE_SESSION_SKIP_RETRANSMIT)
3004             {
3005               rv = 0;
3006               break;
3007             }
3008 
3009           if (message_tag)
3010             (*message_tag)++;
3011           /* In IPMI 2.0, session sequence numbers of 0 are special */
3012           if (session_sequence_number)
3013             {
3014               (*session_sequence_number)++;
3015               if (!(*session_sequence_number))
3016                 (*session_sequence_number)++;
3017             }
3018           if (rq_seq)
3019             *rq_seq = ((*rq_seq) + 1) % (IPMI_LAN_REQUESTER_SEQUENCE_NUMBER_MAX + 1);
3020 
3021           retransmission_count++;
3022 
3023           if (payload_type == IPMI_PAYLOAD_TYPE_RMCPPLUS_OPEN_SESSION_REQUEST
3024               || payload_type == IPMI_PAYLOAD_TYPE_RAKP_MESSAGE_1
3025               || payload_type == IPMI_PAYLOAD_TYPE_RAKP_MESSAGE_3)
3026             {
3027               /* Unlike most packets, the open session request, rakp 1
3028                * and rakp 3 messages have the message tags in a
3029                * non-header field.  So this is a special case.
3030                */
3031               if (fiid_obj_set (obj_cmd_rq, "message_tag", (*message_tag)) < 0)
3032                 {
3033                   API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_cmd_rq);
3034                   goto cleanup;
3035                 }
3036             }
3037 
3038           if (_api_lan_2_0_cmd_send (ctx,
3039                                      lun,
3040                                      net_fn,
3041                                      payload_type,
3042                                      payload_authenticated,
3043                                      payload_encrypted,
3044                                      (session_sequence_number) ? *session_sequence_number : 0,
3045                                      session_id,
3046                                      (rq_seq) ? *rq_seq : 0,
3047                                      authentication_algorithm,
3048                                      integrity_algorithm,
3049                                      confidentiality_algorithm,
3050                                      integrity_key,
3051                                      integrity_key_len,
3052                                      confidentiality_key,
3053                                      confidentiality_key_len,
3054                                      password,
3055                                      password_len,
3056                                      cmd, /* for debug dumping */
3057                                      group_extension, /* for debug dumping */
3058                                      obj_cmd_rq) < 0)
3059             goto cleanup;
3060 
3061           continue;
3062         }
3063 
3064       /* else received a packet */
3065 
3066       if (ctx->flags & IPMI_FLAGS_DEBUG_DUMP)
3067         _api_lan_2_0_dump_rs (ctx,
3068                               authentication_algorithm,
3069                               integrity_algorithm,
3070                               confidentiality_algorithm,
3071                               integrity_key,
3072                               integrity_key_len,
3073                               confidentiality_key,
3074                               confidentiality_key_len,
3075                               pkt,
3076                               recv_len,
3077                               cmd,
3078                               net_fn,
3079                               group_extension,
3080                               obj_cmd_rs);
3081 
3082       if ((ret = unassemble_ipmi_rmcpplus_pkt (authentication_algorithm,
3083                                                integrity_algorithm,
3084                                                confidentiality_algorithm,
3085                                                integrity_key,
3086                                                integrity_key_len,
3087                                                confidentiality_key,
3088                                                confidentiality_key_len,
3089                                                pkt,
3090                                                recv_len,
3091                                                ctx->io.outofband.rs.obj_rmcp_hdr,
3092                                                ctx->io.outofband.rs.obj_rmcpplus_session_hdr,
3093                                                ctx->io.outofband.rs.obj_rmcpplus_payload,
3094                                                ctx->io.outofband.rs.obj_lan_msg_hdr,
3095                                                obj_cmd_rs,
3096                                                ctx->io.outofband.rs.obj_lan_msg_trlr,
3097                                                ctx->io.outofband.rs.obj_rmcpplus_session_trlr,
3098                                                intf_flags)) < 0)
3099         {
3100           API_ERRNO_TO_API_ERRNUM (ctx, errno);
3101           return (-1);
3102         }
3103 
3104       if (!ret)
3105         continue;
3106 
3107       if ((ret = _api_lan_2_0_cmd_wrapper_verify_packet (ctx,
3108                                                          payload_type,
3109                                                          message_tag,
3110                                                          session_sequence_number,
3111                                                          session_id,
3112                                                          rq_seq,
3113                                                          integrity_algorithm,
3114                                                          integrity_key,
3115                                                          integrity_key_len,
3116                                                          password,
3117                                                          password_len,
3118                                                          obj_cmd_rs,
3119                                                          pkt,
3120                                                          recv_len)) < 0)
3121         goto cleanup;
3122 
3123       if (!ret)
3124         continue;
3125 
3126       if (gettimeofday (&ctx->io.outofband.last_received, NULL) < 0)
3127         {
3128           API_ERRNO_TO_API_ERRNUM (ctx, errno);
3129           goto cleanup;
3130         }
3131 
3132       rv = 0;
3133       break;
3134     }
3135 
3136  cleanup:
3137   if (message_tag)
3138     (*message_tag)++;
3139   /* In IPMI 2.0, session sequence numbers of 0 are special */
3140   if (session_sequence_number)
3141     {
3142       (*session_sequence_number)++;
3143       if (!(*session_sequence_number))
3144         (*session_sequence_number)++;
3145     }
3146   if (rq_seq)
3147     *rq_seq = ((*rq_seq) + 1) % (IPMI_LAN_REQUESTER_SEQUENCE_NUMBER_MAX + 1);
3148   return (rv);
3149 }
3150 
3151 int
api_lan_2_0_cmd_wrapper_ipmb(ipmi_ctx_t ctx,fiid_obj_t obj_cmd_rq,fiid_obj_t obj_cmd_rs)3152 api_lan_2_0_cmd_wrapper_ipmb (ipmi_ctx_t ctx,
3153                               fiid_obj_t obj_cmd_rq,
3154                               fiid_obj_t obj_cmd_rs)
3155 {
3156   int recv_len, ret, rv = -1;
3157   unsigned int retransmission_count = 0;
3158   uint8_t pkt[IPMI_MAX_PKT_LEN];
3159   uint8_t cmd = 0;             /* used for debugging */
3160   uint8_t group_extension = 0; /* used for debugging */
3161   uint8_t rq_seq_orig;
3162   uint64_t val;
3163   unsigned int intf_flags = IPMI_INTERFACE_FLAGS_DEFAULT;
3164   fiid_obj_t obj_send_rs = NULL;
3165   ipmi_errnum_type_t obj_rs_errnum;
3166 
3167   assert (ctx
3168           && ctx->magic == IPMI_CTX_MAGIC
3169           && ctx->type == IPMI_DEVICE_LAN_2_0
3170           && ctx->io.outofband.sockfd
3171           && fiid_obj_valid (obj_cmd_rq)
3172           && fiid_obj_packet_valid (obj_cmd_rq) == 1
3173           && fiid_obj_valid (obj_cmd_rs));
3174 
3175   if (ctx->flags & IPMI_FLAGS_NO_LEGAL_CHECK)
3176     intf_flags |= IPMI_INTERFACE_FLAGS_NO_LEGAL_CHECK;
3177 
3178   if (ctx->flags & IPMI_FLAGS_DEBUG_DUMP)
3179     {
3180       /* ignore error, continue on */
3181       if (FIID_OBJ_GET (obj_cmd_rq,
3182                         "cmd",
3183                         &val) < 0)
3184         API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_cmd_rq);
3185       else
3186         cmd = val;
3187 
3188       if (IPMI_NET_FN_GROUP_EXTENSION (ctx->target.net_fn))
3189         {
3190           /* ignore error, continue on */
3191           if (FIID_OBJ_GET (obj_cmd_rq,
3192                             "group_extension_identification",
3193                             &val) < 0)
3194             API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_cmd_rq);
3195           else
3196             group_extension = val;
3197         }
3198     }
3199 
3200   /* for debugging */
3201   ctx->tmpl_ipmb_cmd_rq = fiid_obj_template (obj_cmd_rq);
3202   ctx->tmpl_ipmb_cmd_rs = fiid_obj_template (obj_cmd_rs);
3203 
3204   /* ipmb response packet will use the request sequence number from
3205    * the earlier packet.  Save it for verification.
3206    */
3207 
3208   rq_seq_orig = ctx->io.outofband.rq_seq;
3209 
3210   if (_ipmi_cmd_send_ipmb (ctx,
3211                            obj_cmd_rq,
3212                            &obj_send_rs,
3213                            &obj_rs_errnum) < 0)
3214     goto cleanup;
3215 
3216   while (1)
3217     {
3218       uint8_t payload_authenticated;
3219       uint8_t payload_encrypted;
3220 
3221       if ((ret = _session_timed_out (ctx)) < 0)
3222         break;
3223 
3224       if (ret)
3225         {
3226           API_SET_ERRNUM (ctx, IPMI_ERR_SESSION_TIMEOUT);
3227           break;
3228         }
3229 
3230       /* its ok to use the "request" net_fn, dump code doesn't care */
3231       if ((recv_len = _api_lan_2_0_cmd_recv (ctx,
3232                                              ctx->io.outofband.authentication_algorithm,
3233                                              ctx->io.outofband.integrity_algorithm,
3234                                              ctx->io.outofband.confidentiality_algorithm,
3235                                              ctx->io.outofband.integrity_key_ptr,
3236                                              ctx->io.outofband.integrity_key_len,
3237                                              ctx->io.outofband.confidentiality_key_ptr,
3238                                              ctx->io.outofband.confidentiality_key_len,
3239                                              pkt,
3240                                              IPMI_MAX_PKT_LEN,
3241                                              retransmission_count)) < 0)
3242         {
3243           rv = -1;
3244           break;
3245         }
3246 
3247       if (!recv_len)
3248         {
3249           retransmission_count++;
3250 
3251           /* don't increment sequence numbers, will be done in _ipmi_cmd_send_ipmb */
3252 
3253           /* ipmb response packet will use the request sequence number from
3254            * the earlier packet.  Save it for verification.
3255            */
3256 
3257           rq_seq_orig = ctx->io.outofband.rq_seq;
3258 
3259           if (obj_send_rs) {
3260             fiid_obj_destroy (obj_send_rs);
3261             obj_send_rs = NULL;
3262           }
3263 
3264           if (_ipmi_cmd_send_ipmb (ctx,
3265                                    obj_cmd_rq,
3266                                    &obj_send_rs,
3267                                    &obj_rs_errnum) < 0)
3268             goto cleanup;
3269 
3270           continue;
3271         }
3272 
3273       /* else received a packet */
3274 
3275       if (ctx->flags & IPMI_FLAGS_DEBUG_DUMP)
3276         _api_lan_2_0_dump_rs (ctx,
3277                               ctx->io.outofband.authentication_algorithm,
3278                               ctx->io.outofband.integrity_algorithm,
3279                               ctx->io.outofband.confidentiality_algorithm,
3280                               ctx->io.outofband.integrity_key_ptr,
3281                               ctx->io.outofband.integrity_key_len,
3282                               ctx->io.outofband.confidentiality_key_ptr,
3283                               ctx->io.outofband.confidentiality_key_len,
3284                               pkt,
3285                               recv_len,
3286                               cmd,
3287                               ctx->target.net_fn,
3288                               group_extension,
3289                               obj_cmd_rs);
3290 
3291       if ((ret = unassemble_ipmi_rmcpplus_pkt (ctx->io.outofband.authentication_algorithm,
3292                                                ctx->io.outofband.integrity_algorithm,
3293                                                ctx->io.outofband.confidentiality_algorithm,
3294                                                ctx->io.outofband.integrity_key_ptr,
3295                                                ctx->io.outofband.integrity_key_len,
3296                                                ctx->io.outofband.confidentiality_key_ptr,
3297                                                ctx->io.outofband.confidentiality_key_len,
3298                                                pkt,
3299                                                recv_len,
3300                                                ctx->io.outofband.rs.obj_rmcp_hdr,
3301                                                ctx->io.outofband.rs.obj_rmcpplus_session_hdr,
3302                                                ctx->io.outofband.rs.obj_rmcpplus_payload,
3303                                                ctx->io.outofband.rs.obj_lan_msg_hdr,
3304                                                obj_cmd_rs,
3305                                                ctx->io.outofband.rs.obj_lan_msg_trlr,
3306                                                ctx->io.outofband.rs.obj_rmcpplus_session_trlr,
3307                                                intf_flags)) < 0)
3308         {
3309           API_ERRNO_TO_API_ERRNUM (ctx, errno);
3310           return (-1);
3311         }
3312 
3313       if (!ret)
3314         continue;
3315 
3316       api_lan_2_0_cmd_get_session_parameters (ctx,
3317                                               &payload_authenticated,
3318                                               &payload_encrypted);
3319 
3320       if ((ret = _api_lan_2_0_cmd_wrapper_verify_packet (ctx,
3321                                                          IPMI_PAYLOAD_TYPE_IPMI,
3322                                                          NULL,
3323                                                          &(ctx->io.outofband.session_sequence_number),
3324                                                          ctx->io.outofband.managed_system_session_id,
3325                                                          &rq_seq_orig,
3326                                                          ctx->io.outofband.integrity_algorithm,
3327                                                          ctx->io.outofband.integrity_key_ptr,
3328                                                          ctx->io.outofband.integrity_key_len,
3329                                                          strlen (ctx->io.outofband.password) ? ctx->io.outofband.password : NULL,
3330                                                          strlen (ctx->io.outofband.password),
3331                                                          obj_cmd_rs,
3332                                                          pkt,
3333                                                          recv_len)) < 0)
3334         goto cleanup;
3335 
3336       if (!ret)
3337         continue;
3338 
3339       if (gettimeofday (&(ctx->io.outofband.last_received), NULL) < 0)
3340         {
3341           API_ERRNO_TO_API_ERRNUM (ctx, errno);
3342           goto cleanup;
3343         }
3344 
3345       if (_ipmi_check_ipmb_out_of_order (ctx,
3346                                          obj_cmd_rq,
3347                                          obj_cmd_rs,
3348                                          obj_send_rs,
3349                                          obj_rs_errnum) < 0)
3350         goto cleanup;
3351 
3352       rv = 0;
3353       break;
3354     }
3355 
3356  cleanup:
3357   ctx->io.outofband.session_sequence_number++;
3358   /* rq_seq already incremented via _ipmi_cmd_send_ipmb call */
3359   fiid_template_free (ctx->tmpl_ipmb_cmd_rq);
3360   ctx->tmpl_ipmb_cmd_rq = NULL;
3361   fiid_template_free (ctx->tmpl_ipmb_cmd_rs);
3362   ctx->tmpl_ipmb_cmd_rs = NULL;
3363   fiid_obj_destroy (obj_send_rs);
3364 
3365   return (rv);
3366 }
3367 
3368 int
api_lan_2_0_open_session(ipmi_ctx_t ctx)3369 api_lan_2_0_open_session (ipmi_ctx_t ctx)
3370 {
3371   fiid_obj_t obj_cmd_rq = NULL;
3372   fiid_obj_t obj_cmd_rs = NULL;
3373   uint8_t rmcpplus_status_code;
3374   uint8_t remote_console_random_number[IPMI_REMOTE_CONSOLE_RANDOM_NUMBER_LENGTH];
3375   uint8_t managed_system_random_number[IPMI_MANAGED_SYSTEM_RANDOM_NUMBER_LENGTH];
3376   int managed_system_random_number_len;
3377   uint8_t managed_system_guid[IPMI_MANAGED_SYSTEM_GUID_LENGTH];
3378   int managed_system_guid_len;
3379   uint8_t key_exchange_authentication_code[IPMI_MAX_KEY_EXCHANGE_AUTHENTICATION_CODE_LENGTH];
3380   int key_exchange_authentication_code_len;
3381   uint8_t message_tag;
3382   char *username;
3383   char username_buf[IPMI_MAX_USER_NAME_LENGTH+1];
3384   unsigned int username_len;
3385   char *password;
3386   unsigned int password_len;
3387   uint8_t authentication_algorithm = 0; /* init to 0 to remove gcc warning */
3388   uint8_t requested_maximum_privilege;
3389   uint8_t name_only_lookup;
3390   char *tmp_username_ptr = NULL;
3391   char *tmp_password_ptr = NULL;
3392   void *tmp_k_g_ptr = NULL;
3393   int ret, rv = -1;
3394   uint64_t val;
3395 
3396   assert (ctx
3397           && ctx->magic == IPMI_CTX_MAGIC
3398           && ctx->io.outofband.sockfd
3399           && ctx->type == IPMI_DEVICE_LAN_2_0
3400           && strlen (ctx->io.outofband.username) <= IPMI_MAX_USER_NAME_LENGTH
3401           && strlen (ctx->io.outofband.password) <= IPMI_2_0_MAX_PASSWORD_LENGTH
3402           && IPMI_PRIVILEGE_LEVEL_VALID (ctx->io.outofband.privilege_level)
3403           && IPMI_CIPHER_SUITE_ID_SUPPORTED (ctx->io.outofband.cipher_suite_id)
3404           && ctx->io.outofband.sik_key_ptr == ctx->io.outofband.sik_key
3405           && ctx->io.outofband.sik_key_len == IPMI_MAX_SIK_KEY_LENGTH
3406           && ctx->io.outofband.integrity_key_ptr == ctx->io.outofband.integrity_key
3407           && ctx->io.outofband.integrity_key_len == IPMI_MAX_INTEGRITY_KEY_LENGTH
3408           && ctx->io.outofband.confidentiality_key_ptr == ctx->io.outofband.confidentiality_key
3409           && ctx->io.outofband.confidentiality_key_len == IPMI_MAX_CONFIDENTIALITY_KEY_LENGTH);
3410 
3411   if (_api_lan_rq_seq_init (ctx) < 0)
3412     goto cleanup;
3413 
3414   /* Unlike IPMI 1.5, there is no initial sequence number negotiation, so we don't
3415    * start at a random sequence number.
3416    */
3417   ctx->io.outofband.session_sequence_number = 1;
3418 
3419   if (!(obj_cmd_rq = fiid_obj_create (tmpl_cmd_get_channel_authentication_capabilities_rq)))
3420     {
3421       API_ERRNO_TO_API_ERRNUM (ctx, errno);
3422       goto cleanup;
3423     }
3424   if (!(obj_cmd_rs = fiid_obj_create (tmpl_cmd_get_channel_authentication_capabilities_rs)))
3425     {
3426       API_ERRNO_TO_API_ERRNUM (ctx, errno);
3427       goto cleanup;
3428     }
3429 
3430   if (fill_cmd_get_channel_authentication_capabilities (IPMI_CHANNEL_NUMBER_CURRENT_CHANNEL,
3431                                                         ctx->io.outofband.privilege_level,
3432                                                         IPMI_GET_IPMI_V20_EXTENDED_DATA,
3433                                                         obj_cmd_rq) < 0)
3434     {
3435       API_ERRNO_TO_API_ERRNUM (ctx, errno);
3436       goto cleanup;
3437     }
3438 
3439   /* This portion of the protocol is sent via IPMI 1.5 */
3440   if (api_lan_cmd_wrapper (ctx,
3441                            0,
3442                            IPMI_BMC_IPMB_LUN_BMC,
3443                            IPMI_NET_FN_APP_RQ,
3444                            IPMI_AUTHENTICATION_TYPE_NONE,
3445                            0,
3446                            NULL,
3447                            0,
3448                            &(ctx->io.outofband.rq_seq),
3449                            NULL,
3450                            0,
3451                            obj_cmd_rq,
3452                            obj_cmd_rs) < 0)
3453     {
3454       /* at this point in the protocol, we set a connection timeout */
3455       if (ctx->errnum == IPMI_ERR_SESSION_TIMEOUT)
3456         API_SET_ERRNUM (ctx, IPMI_ERR_CONNECTION_TIMEOUT);
3457       goto cleanup;
3458     }
3459 
3460   if ((ret = ipmi_check_authentication_capabilities_ipmi_2_0 (obj_cmd_rs)) < 0)
3461     {
3462       API_ERRNO_TO_API_ERRNUM (ctx, errno);
3463       goto cleanup;
3464     }
3465 
3466   if (!ret)
3467     {
3468       ctx->errnum = IPMI_ERR_IPMI_2_0_UNAVAILABLE;
3469       goto cleanup;
3470     }
3471 
3472   /* IPMI Workaround
3473    *
3474    * Discovered on an ASUS P5M2 motherboard.
3475    *
3476    * The ASUS motherboard reports incorrect settings of anonymous
3477    * vs. null vs non-null username capabilities.  The workaround is to
3478    * skip all these checks.
3479    *
3480    * Discovered on an ASUS P5MT-R motherboard
3481    *
3482    * K_g status is reported incorrectly too.  Again, skip the checks.
3483    */
3484   if (!(ctx->workaround_flags_outofband_2_0 & IPMI_WORKAROUND_FLAGS_OUTOFBAND_2_0_AUTHENTICATION_CAPABILITIES))
3485     {
3486       if (strlen (ctx->io.outofband.username))
3487         tmp_username_ptr = ctx->io.outofband.username;
3488 
3489       if (strlen (ctx->io.outofband.password))
3490         tmp_password_ptr = ctx->io.outofband.password;
3491 
3492       if ((ret = ipmi_check_authentication_capabilities_username (tmp_username_ptr,
3493                                                                   tmp_password_ptr,
3494                                                                   obj_cmd_rs)) < 0)
3495         {
3496           API_ERRNO_TO_API_ERRNUM (ctx, errno);
3497           goto cleanup;
3498         }
3499 
3500       if (!ret)
3501         {
3502           ctx->errnum = IPMI_ERR_USERNAME_INVALID;
3503           goto cleanup;
3504         }
3505 
3506       if (ctx->io.outofband.k_g_configured)
3507         tmp_k_g_ptr = ctx->io.outofband.k_g;
3508 
3509       if ((ret = ipmi_check_authentication_capabilities_k_g (tmp_k_g_ptr,
3510                                                              obj_cmd_rs)) < 0)
3511         {
3512           API_ERRNO_TO_API_ERRNUM (ctx, errno);
3513           goto cleanup;
3514         }
3515 
3516       if (!ret)
3517         {
3518           API_SET_ERRNUM (ctx, IPMI_ERR_K_G_INVALID);
3519           goto cleanup;
3520         }
3521     }
3522 
3523   fiid_obj_destroy (obj_cmd_rq);
3524   obj_cmd_rq = NULL;
3525   fiid_obj_destroy (obj_cmd_rs);
3526   obj_cmd_rs = NULL;
3527 
3528   if (!(obj_cmd_rq = fiid_obj_create (tmpl_rmcpplus_open_session_request)))
3529     {
3530       API_ERRNO_TO_API_ERRNUM (ctx, errno);
3531       goto cleanup;
3532     }
3533   if (!(obj_cmd_rs = fiid_obj_create (tmpl_rmcpplus_open_session_response)))
3534     {
3535       API_ERRNO_TO_API_ERRNUM (ctx, errno);
3536       goto cleanup;
3537     }
3538 
3539   message_tag = (uint8_t)rand ();
3540 
3541   /* In IPMI 2.0, session_ids of 0 are special */
3542   do
3543     {
3544       if (ipmi_get_random (&(ctx->io.outofband.remote_console_session_id),
3545                            sizeof (ctx->io.outofband.remote_console_session_id)) < 0)
3546         {
3547           API_ERRNO_TO_API_ERRNUM (ctx, errno);
3548           goto cleanup;
3549         }
3550     } while (!ctx->io.outofband.remote_console_session_id);
3551 
3552   if (ipmi_cipher_suite_id_to_algorithms (ctx->io.outofband.cipher_suite_id,
3553                                           &(ctx->io.outofband.authentication_algorithm),
3554                                           &(ctx->io.outofband.integrity_algorithm),
3555                                           &(ctx->io.outofband.confidentiality_algorithm)) < 0)
3556     {
3557       API_ERRNO_TO_API_ERRNUM (ctx, errno);
3558       goto cleanup;
3559     }
3560 
3561   /*
3562    * IPMI Workaround (achu)
3563    *
3564    * Forgotten Motherboard
3565    *
3566    * Cipher suite IDs are attached to specific privilege levels
3567    * rather than a maximum privilege level limit.  So you can only
3568    * authenticate at the configured privilege level rather than a
3569    * privilege level <= to it.
3570    *
3571    * To deal with this situation.  We send the "request highest
3572    * privilege" flag in the open session request.  This should be
3573    * enough to work around this issue but still work with other
3574    * motherboards.
3575    */
3576 
3577   /* IPMI Workaround (achu)
3578    *
3579    * Discovered on SE7520AF2 with Intel Server Management Module
3580    * (Professional Edition)
3581    *
3582    * The Intel's return IPMI_PRIVILEGE_LEVEL_HIGHEST_LEVEL instead
3583    * of an actual privilege, so have to pass the actual privilege
3584    * we want to use.
3585    */
3586 
3587   /* IPMI Workaround (achu)
3588    *
3589    * Discovered on Sun Fire 4100, Inventec 5441/Dell Xanadu II,
3590    * Supermicro X8DTH, Supermicro X8DTG, Supermicro X8DTU, Intel
3591    * S5500WBV/Penguin Relion 700
3592    *
3593    * The remote BMC incorrectly calculates keys using the privilege
3594    * specified in the open session stage rather than the privilege
3595    * used during the RAKP1 stage.  This can be problematic if you
3596    * specify IPMI_PRIVILEGE_LEVEL_HIGHEST_LEVEL during that stage
3597    * instead of a real privilege level.  So we must pass the actual
3598    * privilege we want to use.
3599    */
3600   if (ctx->workaround_flags_outofband_2_0 & IPMI_WORKAROUND_FLAGS_OUTOFBAND_2_0_INTEL_2_0_SESSION
3601       || ctx->workaround_flags_outofband_2_0 & IPMI_WORKAROUND_FLAGS_OUTOFBAND_2_0_SUN_2_0_SESSION
3602       || ctx->workaround_flags_outofband_2_0 & IPMI_WORKAROUND_FLAGS_OUTOFBAND_2_0_OPEN_SESSION_PRIVILEGE)
3603     requested_maximum_privilege = ctx->io.outofband.privilege_level;
3604   else
3605     requested_maximum_privilege = IPMI_PRIVILEGE_LEVEL_HIGHEST_LEVEL;
3606 
3607   if (fill_rmcpplus_open_session (message_tag,
3608                                   requested_maximum_privilege,
3609                                   ctx->io.outofband.remote_console_session_id,
3610                                   ctx->io.outofband.authentication_algorithm,
3611                                   ctx->io.outofband.integrity_algorithm,
3612                                   ctx->io.outofband.confidentiality_algorithm,
3613                                   obj_cmd_rq) < 0)
3614     {
3615       API_ERRNO_TO_API_ERRNUM (ctx, errno);
3616       goto cleanup;
3617     }
3618 
3619   if (api_lan_2_0_cmd_wrapper (ctx,
3620                                0,
3621                                IPMI_BMC_IPMB_LUN_BMC, /* doesn't actually matter here */
3622                                IPMI_NET_FN_APP_RQ, /* doesn't actually matter here */
3623                                IPMI_PAYLOAD_TYPE_RMCPPLUS_OPEN_SESSION_REQUEST,
3624                                IPMI_PAYLOAD_FLAG_UNAUTHENTICATED,
3625                                IPMI_PAYLOAD_FLAG_UNENCRYPTED,
3626                                &message_tag,
3627                                NULL,
3628                                0,
3629                                NULL,
3630                                IPMI_AUTHENTICATION_ALGORITHM_RAKP_NONE,
3631                                IPMI_INTEGRITY_ALGORITHM_NONE,
3632                                IPMI_CONFIDENTIALITY_ALGORITHM_NONE,
3633                                NULL,
3634                                0,
3635                                NULL,
3636                                0,
3637                                NULL,
3638                                0,
3639                                obj_cmd_rq,
3640                                obj_cmd_rs) < 0)
3641     goto cleanup;
3642 
3643   if (FIID_OBJ_GET (obj_cmd_rs,
3644                     "rmcpplus_status_code",
3645                     &val) < 0)
3646     {
3647       API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_cmd_rs);
3648       goto cleanup;
3649     }
3650   rmcpplus_status_code = val;
3651 
3652   if (rmcpplus_status_code != RMCPPLUS_STATUS_NO_ERRORS)
3653     {
3654       if (rmcpplus_status_code == RMCPPLUS_STATUS_NO_CIPHER_SUITE_MATCH_WITH_PROPOSED_SECURITY_ALGORITHMS)
3655         API_SET_ERRNUM (ctx, IPMI_ERR_CIPHER_SUITE_ID_UNAVAILABLE);
3656       else if (rmcpplus_status_code == RMCPPLUS_STATUS_INVALID_ROLE)
3657         API_SET_ERRNUM (ctx, IPMI_ERR_PRIVILEGE_LEVEL_CANNOT_BE_OBTAINED);
3658       else if (rmcpplus_status_code == RMCPPLUS_STATUS_INSUFFICIENT_RESOURCES_TO_CREATE_A_SESSION
3659                || rmcpplus_status_code == RMCPPLUS_STATUS_INSUFFICIENT_RESOURCES_TO_CREATE_A_SESSION_AT_THE_REQUESTED_TIME)
3660         API_SET_ERRNUM (ctx, IPMI_ERR_BMC_BUSY);
3661       else
3662         API_SET_ERRNUM (ctx, IPMI_ERR_BAD_RMCPPLUS_STATUS_CODE);
3663       goto cleanup;
3664     }
3665 
3666   /* IPMI Workaround (achu)
3667    *
3668    * Discovered on SE7520AF2 with Intel Server Management Module
3669    * (Professional Edition)
3670    *
3671    * The Intel's return IPMI_PRIVILEGE_LEVEL_HIGHEST_LEVEL instead
3672    * of an actual privilege, so have to pass the actual privilege
3673    * we want to use.
3674    */
3675   if (ctx->workaround_flags_outofband_2_0 & IPMI_WORKAROUND_FLAGS_OUTOFBAND_2_0_INTEL_2_0_SESSION)
3676     {
3677       uint8_t maximum_privilege_level;
3678 
3679       if (FIID_OBJ_GET (obj_cmd_rs,
3680                         "maximum_privilege_level",
3681                         &val) < 0)
3682         {
3683           API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_cmd_rs);
3684           goto cleanup;
3685         }
3686       maximum_privilege_level = val;
3687 
3688       ret = (maximum_privilege_level == requested_maximum_privilege) ? 1 : 0;
3689     }
3690   else
3691     {
3692       if ((ret = ipmi_check_open_session_maximum_privilege (ctx->io.outofband.privilege_level,
3693                                                             obj_cmd_rs)) < 0)
3694         {
3695           API_ERRNO_TO_API_ERRNUM (ctx, errno);
3696           goto cleanup;
3697         }
3698     }
3699 
3700   if (!ret)
3701     {
3702       API_SET_ERRNUM (ctx, IPMI_ERR_PRIVILEGE_LEVEL_CANNOT_BE_OBTAINED);
3703       goto cleanup;
3704     }
3705 
3706   if (FIID_OBJ_GET (obj_cmd_rs,
3707                     "managed_system_session_id",
3708                     &val) < 0)
3709     {
3710       API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_cmd_rs);
3711       goto cleanup;
3712     }
3713   ctx->io.outofband.managed_system_session_id = val;
3714 
3715   fiid_obj_destroy (obj_cmd_rq);
3716   obj_cmd_rq = NULL;
3717   fiid_obj_destroy (obj_cmd_rs);
3718   obj_cmd_rs = NULL;
3719 
3720   if (!(obj_cmd_rq = fiid_obj_create (tmpl_rmcpplus_rakp_message_1)))
3721     {
3722       API_ERRNO_TO_API_ERRNUM (ctx, errno);
3723       goto cleanup;
3724     }
3725   if (!(obj_cmd_rs = fiid_obj_create (tmpl_rmcpplus_rakp_message_2)))
3726     {
3727       API_ERRNO_TO_API_ERRNUM (ctx, errno);
3728       goto cleanup;
3729     }
3730 
3731   if (ipmi_get_random (remote_console_random_number,
3732                        IPMI_REMOTE_CONSOLE_RANDOM_NUMBER_LENGTH) < 0)
3733     {
3734       API_ERRNO_TO_API_ERRNUM (ctx, errno);
3735       goto cleanup;
3736     }
3737 
3738   /* IPMI Workaround (achu)
3739    *
3740    * Discovered on SE7520AF2 with Intel Server Management Module
3741    * (Professional Edition)
3742    *
3743    * The username must be padded despite explicitly not being
3744    * allowed.  "No Null characters (00h) are allowed in the name".
3745    * Table 13-11 in the IPMI 2.0 spec.
3746    *
3747    * achu: This should only be done for RAKP 1 message, RAKP 2 check,
3748    * and session key creation.
3749    */
3750   if (ctx->workaround_flags_outofband_2_0 & IPMI_WORKAROUND_FLAGS_OUTOFBAND_2_0_INTEL_2_0_SESSION)
3751     {
3752       memset (username_buf, '\0', IPMI_MAX_USER_NAME_LENGTH+1);
3753       if (strlen (ctx->io.outofband.username))
3754         strcpy (username_buf, ctx->io.outofband.username);
3755       username = username_buf;
3756       username_len = IPMI_MAX_USER_NAME_LENGTH;
3757     }
3758   else
3759     {
3760       if (strlen (ctx->io.outofband.username))
3761         username = ctx->io.outofband.username;
3762       else
3763         username = NULL;
3764       username_len = (username) ? strlen (username) : 0;
3765     }
3766 
3767   /* achu: Unlike IPMI 1.5, the length of the username must be actual
3768    * length, it can't be the maximum length.
3769    */
3770   if (fill_rmcpplus_rakp_message_1 (message_tag,
3771                                     ctx->io.outofband.managed_system_session_id,
3772                                     remote_console_random_number,
3773                                     IPMI_REMOTE_CONSOLE_RANDOM_NUMBER_LENGTH,
3774                                     ctx->io.outofband.privilege_level,
3775                                     IPMI_NAME_ONLY_LOOKUP,
3776                                     username,
3777                                     username_len,
3778                                     obj_cmd_rq) < 0)
3779     {
3780       API_ERRNO_TO_API_ERRNUM (ctx, errno);
3781       goto cleanup;
3782     }
3783 
3784   if (api_lan_2_0_cmd_wrapper (ctx,
3785                                0,
3786                                IPMI_BMC_IPMB_LUN_BMC, /* doesn't actually matter here */
3787                                IPMI_NET_FN_APP_RQ, /* doesn't actually matter here */
3788                                IPMI_PAYLOAD_TYPE_RAKP_MESSAGE_1,
3789                                IPMI_PAYLOAD_FLAG_UNAUTHENTICATED,
3790                                IPMI_PAYLOAD_FLAG_UNENCRYPTED,
3791                                &message_tag,
3792                                NULL,
3793                                0,
3794                                NULL,
3795                                IPMI_AUTHENTICATION_ALGORITHM_RAKP_NONE,
3796                                IPMI_INTEGRITY_ALGORITHM_NONE,
3797                                IPMI_CONFIDENTIALITY_ALGORITHM_NONE,
3798                                NULL,
3799                                0,
3800                                NULL,
3801                                0,
3802                                NULL,
3803                                0,
3804                                obj_cmd_rq,
3805                                obj_cmd_rs) < 0)
3806     goto cleanup;
3807 
3808   if (FIID_OBJ_GET (obj_cmd_rs,
3809                     "rmcpplus_status_code",
3810                     &val) < 0)
3811     {
3812       API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_cmd_rs);
3813       goto cleanup;
3814     }
3815   rmcpplus_status_code = val;
3816 
3817   if (rmcpplus_status_code != RMCPPLUS_STATUS_NO_ERRORS)
3818     {
3819       if (rmcpplus_status_code == RMCPPLUS_STATUS_UNAUTHORIZED_NAME)
3820         API_SET_ERRNUM (ctx, IPMI_ERR_USERNAME_INVALID);
3821       else if (rmcpplus_status_code == RMCPPLUS_STATUS_UNAUTHORIZED_ROLE_OR_PRIVILEGE_LEVEL_REQUESTED)
3822         API_SET_ERRNUM (ctx, IPMI_ERR_PRIVILEGE_LEVEL_CANNOT_BE_OBTAINED);
3823       else if (rmcpplus_status_code == RMCPPLUS_STATUS_INSUFFICIENT_RESOURCES_TO_CREATE_A_SESSION
3824                || rmcpplus_status_code == RMCPPLUS_STATUS_INSUFFICIENT_RESOURCES_TO_CREATE_A_SESSION_AT_THE_REQUESTED_TIME)
3825         API_SET_ERRNUM (ctx, IPMI_ERR_BMC_BUSY);
3826       else
3827         API_SET_ERRNUM (ctx, IPMI_ERR_BAD_RMCPPLUS_STATUS_CODE);
3828       goto cleanup;
3829     }
3830 
3831   if ((managed_system_random_number_len = fiid_obj_get_data (obj_cmd_rs,
3832                                                              "managed_system_random_number",
3833                                                              managed_system_random_number,
3834                                                              IPMI_MANAGED_SYSTEM_RANDOM_NUMBER_LENGTH)) < 0)
3835     {
3836       API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_cmd_rs);
3837       goto cleanup;
3838     }
3839 
3840   if ((managed_system_guid_len = fiid_obj_get_data (obj_cmd_rs,
3841                                                     "managed_system_guid",
3842                                                     managed_system_guid,
3843                                                     IPMI_MANAGED_SYSTEM_GUID_LENGTH)) < 0)
3844     {
3845       API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_cmd_rs);
3846       goto cleanup;
3847     }
3848 
3849   if (managed_system_random_number_len != IPMI_MANAGED_SYSTEM_RANDOM_NUMBER_LENGTH
3850       || managed_system_guid_len != IPMI_MANAGED_SYSTEM_GUID_LENGTH)
3851     {
3852       API_SET_ERRNUM (ctx, IPMI_ERR_IPMI_ERROR);
3853       goto cleanup;
3854     }
3855 
3856   if (strlen (ctx->io.outofband.password))
3857     password = ctx->io.outofband.password;
3858   else
3859     password = NULL;
3860   password_len = (password) ? strlen (password) : 0;
3861 
3862   /* IPMI Workaround (achu)
3863    *
3864    * Discovered on SE7520AF2 with Intel Server Management Module
3865    * (Professional Edition)
3866    *
3867    * When the authentication algorithm is HMAC-MD5-128 and the
3868    * password is greater than 16 bytes, the Intel BMC truncates the
3869    * password to 16 bytes when generating keys, hashes, etc.  So we
3870    * have to do the same when generating keys, hashes, etc.
3871    */
3872   if (ctx->workaround_flags_outofband_2_0 & IPMI_WORKAROUND_FLAGS_OUTOFBAND_2_0_INTEL_2_0_SESSION
3873       && ctx->io.outofband.authentication_algorithm == IPMI_AUTHENTICATION_ALGORITHM_RAKP_HMAC_MD5
3874       && password_len > IPMI_1_5_MAX_PASSWORD_LENGTH)
3875     password_len = IPMI_1_5_MAX_PASSWORD_LENGTH;
3876 
3877   if (ctx->workaround_flags_outofband_2_0 & IPMI_WORKAROUND_FLAGS_OUTOFBAND_2_0_SUPERMICRO_2_0_SESSION)
3878     {
3879       uint8_t keybuf[IPMI_MAX_PKT_LEN];
3880       int keybuf_len;
3881 
3882       /* IPMI Workaround (achu)
3883        *
3884        * Discovered on Supermicro H8QME with SIMSO daughter card.
3885        *
3886        * The IPMI 2.0 packet responses for RAKP 2 have payload lengths
3887        * that are off by 1 (i.e. if the payload length should be X,
3888        * the payload length returned in the packet is X + 1)
3889        *
3890        * We fix/adjust for the situation here.
3891        */
3892 
3893       if ((keybuf_len = fiid_obj_get_data (obj_cmd_rs,
3894                                            "key_exchange_authentication_code",
3895                                            keybuf,
3896                                            IPMI_MAX_PKT_LEN)) < 0)
3897         {
3898           API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_cmd_rs);
3899           goto cleanup;
3900         }
3901 
3902       if (ctx->io.outofband.authentication_algorithm == IPMI_AUTHENTICATION_ALGORITHM_RAKP_NONE
3903           && keybuf_len == 1)
3904         {
3905           if (fiid_obj_clear_field (obj_cmd_rs,
3906                                     "key_exchange_authentication_code") < 0)
3907             {
3908               API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_cmd_rs);
3909               goto cleanup;
3910             }
3911         }
3912       else if (ctx->io.outofband.authentication_algorithm == IPMI_AUTHENTICATION_ALGORITHM_RAKP_HMAC_SHA1
3913                && keybuf_len == (IPMI_HMAC_SHA1_DIGEST_LENGTH + 1))
3914         {
3915           if (fiid_obj_set_data (obj_cmd_rs,
3916                                  "key_exchange_authentication_code",
3917                                  keybuf,
3918                                  IPMI_HMAC_SHA1_DIGEST_LENGTH) < 0)
3919             {
3920               API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_cmd_rs);
3921               goto cleanup;
3922             }
3923         }
3924       else if (ctx->io.outofband.authentication_algorithm == IPMI_AUTHENTICATION_ALGORITHM_RAKP_HMAC_MD5
3925                && keybuf_len == (IPMI_HMAC_MD5_DIGEST_LENGTH + 1))
3926         {
3927           if (fiid_obj_set_data (obj_cmd_rs,
3928                                  "key_exchange_authentication_code",
3929                                  keybuf,
3930                                  IPMI_HMAC_MD5_DIGEST_LENGTH) < 0)
3931             {
3932               API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_cmd_rs);
3933               goto cleanup;
3934             }
3935         }
3936       else if (ctx->io.outofband.authentication_algorithm == IPMI_AUTHENTICATION_ALGORITHM_RAKP_HMAC_SHA256
3937                && keybuf_len == (IPMI_HMAC_SHA256_DIGEST_LENGTH + 1))
3938         {
3939           if (fiid_obj_set_data (obj_cmd_rs,
3940                                  "key_exchange_authentication_code",
3941                                  keybuf,
3942                                  IPMI_HMAC_SHA256_DIGEST_LENGTH) < 0)
3943             {
3944               API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_cmd_rs);
3945               goto cleanup;
3946             }
3947         }
3948     }
3949 
3950   /* IPMI Workaround (achu)
3951    *
3952    * Discovered on Sun Fire 4100.
3953    *
3954    * The key exchange authentication code is the wrong length.  We
3955    * need to shorten it.
3956    *
3957    * Notes: Cipher suite 1,2,3 are the ones that use HMAC-SHA1 and
3958    * have the problem.
3959    */
3960   if (ctx->workaround_flags_outofband_2_0 & IPMI_WORKAROUND_FLAGS_OUTOFBAND_2_0_SUN_2_0_SESSION
3961       && (ctx->io.outofband.authentication_algorithm == IPMI_AUTHENTICATION_ALGORITHM_RAKP_HMAC_SHA1))
3962     {
3963       uint8_t buf[IPMI_MAX_KEY_EXCHANGE_AUTHENTICATION_CODE_LENGTH];
3964       int buf_len;
3965 
3966       if ((buf_len = fiid_obj_get_data (obj_cmd_rs,
3967                                         "key_exchange_authentication_code",
3968                                         buf,
3969                                         IPMI_MAX_KEY_EXCHANGE_AUTHENTICATION_CODE_LENGTH)) < 0)
3970         {
3971           API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_cmd_rs);
3972           goto cleanup;
3973         }
3974 
3975       if (buf_len == (IPMI_HMAC_SHA1_DIGEST_LENGTH + 1))
3976         {
3977           if (fiid_obj_clear_field (obj_cmd_rs,
3978                                     "key_exchange_authentication_code") < 0)
3979             {
3980               API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_cmd_rs);
3981               goto cleanup;
3982             }
3983 
3984           if (fiid_obj_set_data (obj_cmd_rs,
3985                                  "key_exchange_authentication_code",
3986                                  buf,
3987                                  IPMI_HMAC_SHA1_DIGEST_LENGTH) < 0)
3988             {
3989               API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_cmd_rs);
3990               goto cleanup;
3991             }
3992         }
3993     }
3994 
3995   if ((ret = ipmi_rmcpplus_check_rakp_2_key_exchange_authentication_code (ctx->io.outofband.authentication_algorithm,
3996                                                                           password,
3997                                                                           password_len,
3998                                                                           ctx->io.outofband.remote_console_session_id,
3999                                                                           ctx->io.outofband.managed_system_session_id,
4000                                                                           remote_console_random_number,
4001                                                                           IPMI_REMOTE_CONSOLE_RANDOM_NUMBER_LENGTH,
4002                                                                           managed_system_random_number,
4003                                                                           managed_system_random_number_len,
4004                                                                           managed_system_guid,
4005                                                                           managed_system_guid_len,
4006                                                                           IPMI_NAME_ONLY_LOOKUP,
4007                                                                           ctx->io.outofband.privilege_level,
4008                                                                           username,
4009                                                                           username_len,
4010                                                                           obj_cmd_rs)) < 0)
4011     {
4012       API_ERRNO_TO_API_ERRNUM (ctx, errno);
4013       goto cleanup;
4014     }
4015 
4016   if (!ret)
4017     {
4018       /* IPMI Compliance Issue
4019        *
4020        * On some systems, password could be correct, but privilege is
4021        * too high.  The error is b/c the privilege error is not
4022        * handled properly in the open session stage (i.e. they tell me
4023        * I can authenticate at a high privilege level, that in reality
4024        * is not allowed).  Dunno how to deal with this.
4025        */
4026       API_SET_ERRNUM (ctx, IPMI_ERR_PASSWORD_INVALID);
4027       goto cleanup;
4028     }
4029 
4030   /* achu: note, for INTEL_2_0 workaround, this must have the username/password adjustments */
4031   if (ipmi_calculate_rmcpplus_session_keys (ctx->io.outofband.authentication_algorithm,
4032                                             ctx->io.outofband.integrity_algorithm,
4033                                             ctx->io.outofband.confidentiality_algorithm,
4034                                             password,
4035                                             password_len,
4036                                             (ctx->io.outofband.k_g_configured) ? ctx->io.outofband.k_g : NULL,
4037                                             (ctx->io.outofband.k_g_configured) ? IPMI_MAX_K_G_LENGTH : 0,
4038                                             remote_console_random_number,
4039                                             IPMI_REMOTE_CONSOLE_RANDOM_NUMBER_LENGTH,
4040                                             managed_system_random_number,
4041                                             IPMI_MANAGED_SYSTEM_RANDOM_NUMBER_LENGTH,
4042                                             IPMI_NAME_ONLY_LOOKUP,
4043                                             ctx->io.outofband.privilege_level,
4044                                             username,
4045                                             username_len,
4046                                             &(ctx->io.outofband.sik_key_ptr),
4047                                             &(ctx->io.outofband.sik_key_len),
4048                                             &(ctx->io.outofband.integrity_key_ptr),
4049                                             &(ctx->io.outofband.integrity_key_len),
4050                                             &(ctx->io.outofband.confidentiality_key_ptr),
4051                                             &(ctx->io.outofband.confidentiality_key_len)) < 0)
4052     {
4053       API_ERRNO_TO_API_ERRNUM (ctx, errno);
4054       goto cleanup;
4055     }
4056 
4057   /* achu: If INTEL_2_0 workaround is set, get back to original username &
4058    * username_len, because that isn't needed for the RAKP3/4 part.
4059    */
4060   if (ctx->workaround_flags_outofband_2_0 & IPMI_WORKAROUND_FLAGS_OUTOFBAND_2_0_INTEL_2_0_SESSION)
4061     {
4062       if (strlen (ctx->io.outofband.username))
4063         username = ctx->io.outofband.username;
4064       else
4065         username = NULL;
4066       username_len = (username) ? strlen (username) : 0;
4067     }
4068 
4069   /* IPMI Workaround (achu)
4070    *
4071    * Discovered on SE7520AF2 with Intel Server Management Module
4072    * (Professional Edition)
4073    *
4074    * For some reason we have to create this key with the name only
4075    * lookup turned off.  I was skeptical about this actually being
4076    * a bug until I saw that the ipmitool folks implemented the
4077    * same workaround.
4078    */
4079   if (ctx->workaround_flags_outofband_2_0 & IPMI_WORKAROUND_FLAGS_OUTOFBAND_2_0_INTEL_2_0_SESSION)
4080     name_only_lookup = IPMI_USER_NAME_PRIVILEGE_LOOKUP;
4081   else
4082     name_only_lookup = IPMI_NAME_ONLY_LOOKUP;
4083 
4084   if ((key_exchange_authentication_code_len = ipmi_calculate_rakp_3_key_exchange_authentication_code (ctx->io.outofband.authentication_algorithm,
4085                                                                                                       password,
4086                                                                                                       password_len,
4087                                                                                                       managed_system_random_number,
4088                                                                                                       managed_system_random_number_len,
4089                                                                                                       ctx->io.outofband.remote_console_session_id,
4090                                                                                                       name_only_lookup,
4091                                                                                                       ctx->io.outofband.privilege_level,
4092                                                                                                       username,
4093                                                                                                       username_len,
4094                                                                                                       key_exchange_authentication_code,
4095                                                                                                       IPMI_MAX_KEY_EXCHANGE_AUTHENTICATION_CODE_LENGTH)) < 0)
4096     {
4097       API_ERRNO_TO_API_ERRNUM (ctx, errno);
4098       goto cleanup;
4099     }
4100 
4101   fiid_obj_destroy (obj_cmd_rq);
4102   obj_cmd_rq = NULL;
4103   fiid_obj_destroy (obj_cmd_rs);
4104   obj_cmd_rs = NULL;
4105 
4106   if (!(obj_cmd_rq = fiid_obj_create (tmpl_rmcpplus_rakp_message_3)))
4107     {
4108       API_ERRNO_TO_API_ERRNUM (ctx, errno);
4109       goto cleanup;
4110     }
4111   if (!(obj_cmd_rs = fiid_obj_create (tmpl_rmcpplus_rakp_message_4)))
4112     {
4113       API_ERRNO_TO_API_ERRNUM (ctx, errno);
4114       goto cleanup;
4115     }
4116 
4117   if (fill_rmcpplus_rakp_message_3 (message_tag,
4118                                     RMCPPLUS_STATUS_NO_ERRORS,
4119                                     ctx->io.outofband.managed_system_session_id,
4120                                     key_exchange_authentication_code,
4121                                     key_exchange_authentication_code_len,
4122                                     obj_cmd_rq) < 0)
4123     {
4124       API_ERRNO_TO_API_ERRNUM (ctx, errno);
4125       goto cleanup;
4126     }
4127 
4128   if (api_lan_2_0_cmd_wrapper (ctx,
4129                                0,
4130                                IPMI_BMC_IPMB_LUN_BMC, /* doesn't actually matter here */
4131                                IPMI_NET_FN_APP_RQ, /* doesn't actually matter here */
4132                                IPMI_PAYLOAD_TYPE_RAKP_MESSAGE_3,
4133                                IPMI_PAYLOAD_FLAG_UNAUTHENTICATED,
4134                                IPMI_PAYLOAD_FLAG_UNENCRYPTED,
4135                                &message_tag,
4136                                NULL,
4137                                0,
4138                                NULL,
4139                                IPMI_AUTHENTICATION_ALGORITHM_RAKP_NONE,
4140                                IPMI_INTEGRITY_ALGORITHM_NONE,
4141                                IPMI_CONFIDENTIALITY_ALGORITHM_NONE,
4142                                NULL,
4143                                0,
4144                                NULL,
4145                                0,
4146                                NULL,
4147                                0,
4148                                obj_cmd_rq,
4149                                obj_cmd_rs) < 0)
4150     goto cleanup;
4151 
4152   if (FIID_OBJ_GET (obj_cmd_rs,
4153                     "rmcpplus_status_code",
4154                     &val) < 0)
4155     {
4156       API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_cmd_rs);
4157       goto cleanup;
4158     }
4159   rmcpplus_status_code = val;
4160 
4161   if (rmcpplus_status_code != RMCPPLUS_STATUS_NO_ERRORS)
4162     {
4163       if (rmcpplus_status_code == RMCPPLUS_STATUS_INSUFFICIENT_RESOURCES_TO_CREATE_A_SESSION
4164           || rmcpplus_status_code == RMCPPLUS_STATUS_INSUFFICIENT_RESOURCES_TO_CREATE_A_SESSION_AT_THE_REQUESTED_TIME)
4165         API_SET_ERRNUM (ctx, IPMI_ERR_BMC_BUSY);
4166       else if (rmcpplus_status_code == RMCPPLUS_STATUS_INVALID_INTEGRITY_CHECK_VALUE)
4167         /* XXX: achu: some systems, password could be correct, but
4168          * privilege used in hashing is incorrect on the BMC side
4169          * (OPEN_SESSION_PRIVILEGE workaround).
4170          */
4171         API_SET_ERRNUM (ctx, IPMI_ERR_PASSWORD_INVALID);
4172       else
4173         API_SET_ERRNUM (ctx, IPMI_ERR_BAD_RMCPPLUS_STATUS_CODE);
4174       goto cleanup;
4175     }
4176 
4177   /* IPMI Workaround (achu)
4178    *
4179    * Discovered on SE7520AF2 with Intel Server Management Module
4180    * (Professional Edition)
4181    *
4182    * For some reason, the intel ipmi 2.0 responds with the integrity
4183    * check value based on the integrity algorithm instead of the
4184    * authentication algorithm.
4185    *
4186    * Thanks to the ipmitool folks (ipmitool.sourceforge.net) for this
4187    * one.  Would have taken me awhile to figure this one out :-)
4188    */
4189 
4190   if (ctx->workaround_flags_outofband_2_0 & IPMI_WORKAROUND_FLAGS_OUTOFBAND_2_0_INTEL_2_0_SESSION)
4191     {
4192       if (ctx->io.outofband.integrity_algorithm == IPMI_INTEGRITY_ALGORITHM_NONE)
4193         authentication_algorithm = IPMI_AUTHENTICATION_ALGORITHM_RAKP_NONE;
4194       else if (ctx->io.outofband.integrity_algorithm == IPMI_INTEGRITY_ALGORITHM_HMAC_SHA1_96)
4195         authentication_algorithm = IPMI_AUTHENTICATION_ALGORITHM_RAKP_HMAC_SHA1;
4196       else if (ctx->io.outofband.integrity_algorithm == IPMI_INTEGRITY_ALGORITHM_HMAC_MD5_128)
4197         authentication_algorithm = IPMI_AUTHENTICATION_ALGORITHM_RAKP_HMAC_MD5;
4198       else if (ctx->io.outofband.integrity_algorithm == IPMI_INTEGRITY_ALGORITHM_MD5_128)
4199         {
4200           /* achu: I have thus far been unable to reverse engineer this
4201            * corner case.  Since we cannot provide a reasonable two
4202            * part authentication, we're going to error out.
4203            */
4204           API_SET_ERRNUM (ctx, IPMI_ERR_IPMI_ERROR);
4205           goto cleanup;
4206         }
4207     }
4208   else
4209     authentication_algorithm = ctx->io.outofband.authentication_algorithm;
4210 
4211   /* IPMI Workaround (achu)
4212    *
4213    * Discovered on Supermicro X8DTG, Supermicro X8DTU, Intel
4214    * S5500WBV/Penguin Relion 700
4215    *
4216    * For whatever reason, with cipher suite 0, the RAKP 4 response
4217    * returns with an Integrity Check Value when it should be empty.
4218    */
4219 
4220   if (ctx->workaround_flags_outofband_2_0 & IPMI_WORKAROUND_FLAGS_OUTOFBAND_2_0_NON_EMPTY_INTEGRITY_CHECK_VALUE
4221       && !ctx->io.outofband.cipher_suite_id)
4222     {
4223       if (fiid_obj_clear_field (obj_cmd_rs,
4224                                 "integrity_check_value") < 0)
4225         {
4226           API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_cmd_rs);
4227           goto cleanup;
4228         }
4229     }
4230 
4231   if ((ret = ipmi_rmcpplus_check_rakp_4_integrity_check_value (authentication_algorithm,
4232                                                                ctx->io.outofband.sik_key_ptr,
4233                                                                ctx->io.outofband.sik_key_len,
4234                                                                remote_console_random_number,
4235                                                                IPMI_REMOTE_CONSOLE_RANDOM_NUMBER_LENGTH,
4236                                                                ctx->io.outofband.managed_system_session_id,
4237                                                                managed_system_guid,
4238                                                                managed_system_guid_len,
4239                                                                obj_cmd_rs)) < 0)
4240     {
4241       API_ERRNO_TO_API_ERRNUM (ctx, errno);
4242       goto cleanup;
4243     }
4244 
4245   if (!ret)
4246     {
4247       API_SET_ERRNUM (ctx, IPMI_ERR_K_G_INVALID);
4248       goto cleanup;
4249     }
4250 
4251   fiid_obj_destroy (obj_cmd_rq);
4252   obj_cmd_rq = NULL;
4253   fiid_obj_destroy (obj_cmd_rs);
4254   obj_cmd_rs = NULL;
4255 
4256   /* if privilege_level == IPMI_PRIVILEGE_LEVEL_USER we shouldn't have
4257    * to call this, b/c it should be USER by default.  But I don't
4258    * trust IPMI implementations.  Do it anyways.
4259    */
4260 
4261   /* achu: At this point in time, the session is actually setup
4262    * legitimately, so we can use the actual set session privilege
4263    * level API function.
4264    */
4265 
4266   if (!(obj_cmd_rs = fiid_obj_create (tmpl_cmd_set_session_privilege_level_rs)))
4267     {
4268       API_ERRNO_TO_API_ERRNUM (ctx, errno);
4269       goto cleanup;
4270     }
4271 
4272   if (ipmi_cmd_set_session_privilege_level (ctx,
4273                                             ctx->io.outofband.privilege_level,
4274                                             obj_cmd_rs) < 0)
4275     {
4276       if (ctx->errnum == IPMI_ERR_BAD_COMPLETION_CODE)
4277         {
4278           if (ipmi_check_completion_code (obj_cmd_rs, IPMI_COMP_CODE_SET_SESSION_PRIVILEGE_LEVEL_REQUESTED_LEVEL_NOT_AVAILABLE_FOR_USER) == 1
4279               || ipmi_check_completion_code (obj_cmd_rs, IPMI_COMP_CODE_SET_SESSION_PRIVILEGE_LEVEL_REQUESTED_LEVEL_EXCEEDS_USER_PRIVILEGE_LIMIT) == 1)
4280             API_SET_ERRNUM (ctx, IPMI_ERR_PRIVILEGE_LEVEL_CANNOT_BE_OBTAINED);
4281         }
4282       ERR_TRACE (ipmi_ctx_strerror (ctx->errnum), ctx->errnum);
4283       goto cleanup;
4284     }
4285 
4286   rv = 0;
4287  cleanup:
4288   fiid_obj_destroy (obj_cmd_rq);
4289   fiid_obj_destroy (obj_cmd_rs);
4290   return (rv);
4291 }
4292 
4293 int
api_lan_2_0_close_session(ipmi_ctx_t ctx)4294 api_lan_2_0_close_session (ipmi_ctx_t ctx)
4295 {
4296   fiid_obj_t obj_cmd_rq = NULL;
4297   fiid_obj_t obj_cmd_rs = NULL;
4298   uint8_t payload_authenticated;
4299   uint8_t payload_encrypted;
4300   unsigned int internal_workaround_flags = 0;
4301   int ret, rv = -1;
4302 
4303   /* Do not use ipmi_cmd_close_session(), we use a close session retransmit workaround */
4304 
4305   assert (ctx
4306           && ctx->magic == IPMI_CTX_MAGIC
4307           && ctx->type == IPMI_DEVICE_LAN_2_0
4308           && ctx->io.outofband.sockfd);
4309 
4310   if (!(obj_cmd_rq = fiid_obj_create (tmpl_cmd_close_session_rq)))
4311     {
4312       API_ERRNO_TO_API_ERRNUM (ctx, errno);
4313       return (-1);
4314     }
4315 
4316   if (!(obj_cmd_rs = fiid_obj_create (tmpl_cmd_close_session_rs)))
4317     {
4318       API_ERRNO_TO_API_ERRNUM (ctx, errno);
4319       return (-1);
4320     }
4321 
4322   if (fill_cmd_close_session (ctx->io.outofband.managed_system_session_id,
4323                               NULL,
4324                               obj_cmd_rq) < 0)
4325     {
4326       API_ERRNO_TO_API_ERRNUM (ctx, errno);
4327       goto cleanup;
4328     }
4329 
4330   api_lan_2_0_cmd_get_session_parameters (ctx,
4331                                           &payload_authenticated,
4332                                           &payload_encrypted);
4333 
4334   internal_workaround_flags |= IPMI_INTERNAL_WORKAROUND_FLAGS_CLOSE_SESSION_SKIP_RETRANSMIT;
4335 
4336   if (api_lan_2_0_cmd_wrapper (ctx,
4337                                internal_workaround_flags,
4338                                IPMI_BMC_IPMB_LUN_BMC,
4339                                IPMI_NET_FN_APP_RQ,
4340                                IPMI_PAYLOAD_TYPE_IPMI,
4341                                payload_authenticated,
4342                                payload_encrypted,
4343                                NULL,
4344                                &(ctx->io.outofband.session_sequence_number),
4345                                ctx->io.outofband.managed_system_session_id,
4346                                &(ctx->io.outofband.rq_seq),
4347                                ctx->io.outofband.authentication_algorithm,
4348                                ctx->io.outofband.integrity_algorithm,
4349                                ctx->io.outofband.confidentiality_algorithm,
4350                                ctx->io.outofband.integrity_key_ptr,
4351                                ctx->io.outofband.integrity_key_len,
4352                                ctx->io.outofband.confidentiality_key_ptr,
4353                                ctx->io.outofband.confidentiality_key_len,
4354                                strlen (ctx->io.outofband.password) ? ctx->io.outofband.password : NULL,
4355                                strlen (ctx->io.outofband.password),
4356                                obj_cmd_rq,
4357                                obj_cmd_rs) < 0)
4358     goto cleanup;
4359 
4360   /* Check completion code just for tracing, but don't return error */
4361 
4362   if ((ret = ipmi_check_completion_code_success (obj_cmd_rs)) < 0)
4363     {
4364       API_ERRNO_TO_API_ERRNUM (ctx, errno);
4365       goto out;
4366     }
4367 
4368   if (!ret)
4369     {
4370       API_BAD_RESPONSE_TO_API_ERRNUM (ctx, obj_cmd_rs);
4371       goto out;
4372     }
4373 
4374  out:
4375   rv = 0;
4376  cleanup:
4377   fiid_obj_destroy (obj_cmd_rq);
4378   fiid_obj_destroy (obj_cmd_rs);
4379   return (rv);
4380 }
4381