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 (¤t, NULL) < 0)
152 {
153 API_ERRNO_TO_API_ERRNUM (ctx, errno);
154 return (-1);
155 }
156
157 return (timercmp (¤t, &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 (¤t, 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 (¤t, 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