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 <limits.h>
29 #include <assert.h>
30 #include <errno.h>
31
32 #include "freeipmi/cmds/ipmi-messaging-support-cmds.h"
33 #include "freeipmi/fiid/fiid.h"
34 #include "freeipmi/interface/ipmi-interface.h"
35 #include "freeipmi/interface/ipmi-lan-interface.h"
36 #include "freeipmi/interface/rmcp-interface.h"
37 #include "freeipmi/spec/ipmi-authentication-type-spec.h"
38 #include "freeipmi/spec/ipmi-ipmb-lun-spec.h"
39 #include "freeipmi/spec/ipmi-netfn-spec.h"
40 #include "freeipmi/spec/ipmi-slave-address-spec.h"
41 #include "freeipmi/util/ipmi-util.h"
42
43 #include "ipmi-network.h"
44 #include "libcommon/ipmi-fiid-util.h"
45 #include "libcommon/ipmi-fill-util.h"
46 #include "libcommon/ipmi-md2.h"
47 #include "libcommon/ipmi-md5.h"
48 #include "libcommon/ipmi-trace.h"
49
50 #include "freeipmi-portability.h"
51 #include "secure.h"
52
53 #define IPMI_LAN_PKT_PAD_SIZE 1
54
55 /* authentication code may contain plain password, always securely clear it */
56 fiid_template_t tmpl_lan_session_hdr =
57 {
58 { 8, "authentication_type", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
59 { 32, "session_sequence_number", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
60 { 32, "session_id", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
61 { 128, "authentication_code", FIID_FIELD_OPTIONAL | FIID_FIELD_LENGTH_FIXED | FIID_FIELD_SECURE_MEMSET_ON_CLEAR},
62 { 8, "ipmi_msg_len", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
63 { 0, "", 0}
64 };
65
66 /* IPMI LAN Message Request Header */
67 fiid_template_t tmpl_lan_msg_hdr_rq =
68 {
69 { 8, "rs_addr", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
70 { 2, "rs_lun", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
71 { 6, "net_fn", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
72 { 8, "checksum1", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
73 { 8, "rq_addr", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
74 { 2, "rq_lun", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
75 { 6, "rq_seq", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
76 { 0, "", 0}
77 };
78
79 /* IPMI LAN Message Response Header */
80 fiid_template_t tmpl_lan_msg_hdr_rs =
81 {
82 { 8, "rq_addr", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
83 { 2, "rq_lun", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
84 { 6, "net_fn", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
85 { 8, "checksum1", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
86 { 8, "rs_addr", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
87 { 2, "rs_lun", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
88 { 6, "rq_seq", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
89 { 0, "", 0}
90 };
91
92 /* IPMI LAN Message Trailer */
93 fiid_template_t tmpl_lan_msg_trlr =
94 {
95 { 8, "checksum2", FIID_FIELD_REQUIRED | FIID_FIELD_LENGTH_FIXED},
96 { 0, "", 0}
97 };
98
99 int
fill_lan_session_hdr(uint8_t authentication_type,uint32_t session_sequence_number,uint32_t session_id,fiid_obj_t obj_lan_session_hdr)100 fill_lan_session_hdr (uint8_t authentication_type,
101 uint32_t session_sequence_number,
102 uint32_t session_id,
103 fiid_obj_t obj_lan_session_hdr)
104 {
105 if (!IPMI_AUTHENTICATION_TYPE_VALID (authentication_type)
106 || !fiid_obj_valid (obj_lan_session_hdr))
107 {
108 SET_ERRNO (EINVAL);
109 return (-1);
110 }
111
112 if (FIID_OBJ_TEMPLATE_COMPARE (obj_lan_session_hdr, tmpl_lan_session_hdr) < 0)
113 {
114 ERRNO_TRACE (errno);
115 return (-1);
116 }
117
118 FILL_FIID_OBJ_CLEAR (obj_lan_session_hdr);
119 FILL_FIID_OBJ_SET (obj_lan_session_hdr, "authentication_type", authentication_type);
120 FILL_FIID_OBJ_SET (obj_lan_session_hdr, "session_sequence_number", session_sequence_number);
121 FILL_FIID_OBJ_SET (obj_lan_session_hdr, "session_id", session_id);
122
123 /* authentication_code_data calculated in assemble_ipmi_lan_pkt */
124 /* ipmi_msg_len calculated in assemble_ipmi_lan_pkt */
125
126 return (0);
127 }
128
129 int
fill_lan_msg_hdr(uint8_t rs_addr,uint8_t net_fn,uint8_t rs_lun,uint8_t rq_seq,fiid_obj_t obj_lan_msg_hdr)130 fill_lan_msg_hdr (uint8_t rs_addr,
131 uint8_t net_fn,
132 uint8_t rs_lun,
133 uint8_t rq_seq,
134 fiid_obj_t obj_lan_msg_hdr)
135 {
136 uint8_t checksum_buf[1024];
137 int checksum_len;
138 uint8_t checksum;
139
140 if (!IPMI_NET_FN_VALID (net_fn)
141 || !IPMI_BMC_LUN_VALID (rs_lun)
142 || (rq_seq > IPMI_LAN_REQUESTER_SEQUENCE_NUMBER_MAX)
143 || !fiid_obj_valid (obj_lan_msg_hdr))
144 {
145 SET_ERRNO (EINVAL);
146 return (-1);
147 }
148
149 if (FIID_OBJ_TEMPLATE_COMPARE (obj_lan_msg_hdr, tmpl_lan_msg_hdr_rq) < 0)
150 {
151 ERRNO_TRACE (errno);
152 return (-1);
153 }
154
155 FILL_FIID_OBJ_CLEAR (obj_lan_msg_hdr);
156 FILL_FIID_OBJ_SET (obj_lan_msg_hdr, "rs_addr", rs_addr);
157 FILL_FIID_OBJ_SET (obj_lan_msg_hdr, "net_fn", net_fn);
158 FILL_FIID_OBJ_SET (obj_lan_msg_hdr, "rs_lun", rs_lun);
159
160 if ((checksum_len = fiid_obj_get_block (obj_lan_msg_hdr,
161 "rs_addr",
162 "net_fn",
163 checksum_buf,
164 1024)) < 0)
165 {
166 FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_msg_hdr);
167 return (-1);
168 }
169
170 checksum = ipmi_checksum (checksum_buf, checksum_len);
171 FILL_FIID_OBJ_SET (obj_lan_msg_hdr, "checksum1", checksum);
172 FILL_FIID_OBJ_SET (obj_lan_msg_hdr, "rq_addr", IPMI_LAN_SOFTWARE_ID_REMOTE_CONSOLE_SOFTWARE);
173 FILL_FIID_OBJ_SET (obj_lan_msg_hdr, "rq_lun", IPMI_BMC_IPMB_LUN_BMC);
174 FILL_FIID_OBJ_SET (obj_lan_msg_hdr, "rq_seq", rq_seq);
175
176 return (0);
177 }
178
179 static int
_ipmi_lan_pkt_rq_min_size(uint8_t authentication_type,fiid_obj_t obj_cmd)180 _ipmi_lan_pkt_rq_min_size (uint8_t authentication_type, fiid_obj_t obj_cmd)
181 {
182 unsigned int msg_len = 0;
183 int len;
184
185 assert (IPMI_1_5_AUTHENTICATION_TYPE_VALID (authentication_type) && fiid_obj_valid (obj_cmd));
186
187 if ((len = fiid_template_len_bytes (tmpl_rmcp_hdr)) < 0)
188 {
189 ERRNO_TRACE (errno);
190 return (-1);
191 }
192 msg_len += len;
193
194 if ((len = fiid_template_len_bytes (tmpl_lan_msg_hdr_rq)) < 0)
195 {
196 ERRNO_TRACE (errno);
197 return (-1);
198 }
199 msg_len += len;
200
201 if ((len = fiid_template_len_bytes (tmpl_lan_msg_trlr)) < 0)
202 {
203 ERRNO_TRACE (errno);
204 return (-1);
205 }
206 msg_len += len;
207
208 if ((len = fiid_template_block_len_bytes (tmpl_lan_session_hdr,
209 "authentication_type",
210 "session_id")) < 0)
211 {
212 ERRNO_TRACE (errno);
213 return (-1);
214 }
215 msg_len += len;
216
217 if (authentication_type == IPMI_AUTHENTICATION_TYPE_MD2
218 || authentication_type == IPMI_AUTHENTICATION_TYPE_MD5
219 || authentication_type == IPMI_AUTHENTICATION_TYPE_STRAIGHT_PASSWORD_KEY
220 || authentication_type == IPMI_AUTHENTICATION_TYPE_OEM_PROP)
221 msg_len += IPMI_1_5_MAX_PASSWORD_LENGTH;
222
223 if ((len = fiid_template_field_len_bytes (tmpl_lan_session_hdr, "ipmi_msg_len")) < 0)
224 {
225 ERRNO_TRACE (errno);
226 return (-1);
227 }
228 msg_len += len;
229
230 if ((len = fiid_obj_len_bytes (obj_cmd)) < 0)
231 {
232 FIID_OBJECT_ERROR_TO_ERRNO (obj_cmd);
233 return (-1);
234 }
235
236 msg_len += len;
237
238 return (msg_len);
239 }
240
241 /*
242 Complete IPMI LAN Request Packet
243 +----------------------+
244 | RMCP |
245 | Session |
246 | Message |
247 | Command |
248 | Data |
249 | Checksum |
250 +----------------------+
251 */
252
253 int
assemble_ipmi_lan_pkt(fiid_obj_t obj_rmcp_hdr,fiid_obj_t obj_lan_session_hdr,fiid_obj_t obj_lan_msg_hdr,fiid_obj_t obj_cmd,const void * authentication_code_data,unsigned int authentication_code_data_len,void * pkt,unsigned int pkt_len,unsigned int flags)254 assemble_ipmi_lan_pkt (fiid_obj_t obj_rmcp_hdr,
255 fiid_obj_t obj_lan_session_hdr,
256 fiid_obj_t obj_lan_msg_hdr,
257 fiid_obj_t obj_cmd,
258 const void *authentication_code_data,
259 unsigned int authentication_code_data_len,
260 void *pkt,
261 unsigned int pkt_len,
262 unsigned int flags)
263 {
264 uint8_t authentication_type;
265 uint64_t val;
266 unsigned int indx = 0;
267 int required_len;
268 void *authentication_code_field_ptr = NULL;
269 void *checksum_data_ptr = NULL;
270 void *msg_data_ptr = NULL;
271 void *ipmi_msg_len_ptr = NULL;
272 unsigned int msg_data_count = 0;
273 unsigned int checksum_data_count = 0;
274 uint8_t ipmi_msg_len;
275 fiid_obj_t obj_lan_msg_trlr = NULL;
276 uint8_t pwbuf[IPMI_1_5_MAX_PASSWORD_LENGTH];
277 uint8_t checksum;
278 int len, rv = -1;
279 unsigned int flags_mask = 0;
280
281 if (!fiid_obj_valid (obj_rmcp_hdr)
282 || !fiid_obj_valid (obj_lan_session_hdr)
283 || !fiid_obj_valid (obj_lan_msg_hdr)
284 || !fiid_obj_valid (obj_cmd)
285 || (authentication_code_data && authentication_code_data_len > IPMI_1_5_MAX_PASSWORD_LENGTH)
286 || !pkt
287 || (flags & ~flags_mask))
288 {
289 SET_ERRNO (EINVAL);
290 return (-1);
291 }
292
293 if (FIID_OBJ_TEMPLATE_COMPARE (obj_rmcp_hdr, tmpl_rmcp_hdr) < 0)
294 {
295 ERRNO_TRACE (errno);
296 return (-1);
297 }
298 if (FIID_OBJ_TEMPLATE_COMPARE (obj_lan_session_hdr, tmpl_lan_session_hdr) < 0)
299 {
300 ERRNO_TRACE (errno);
301 return (-1);
302 }
303 if (FIID_OBJ_TEMPLATE_COMPARE (obj_lan_msg_hdr, tmpl_lan_msg_hdr_rq) < 0)
304 {
305 ERRNO_TRACE (errno);
306 return (-1);
307 }
308
309 if (FIID_OBJ_PACKET_VALID (obj_rmcp_hdr) < 0)
310 {
311 FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcp_hdr);
312 return (-1);
313 }
314
315 /*
316 * ipmi_msg_len is calculated in this function, so we can't use
317 * fiid_obj_packet_valid() on obj_lan_session_hdr b/c ipmi_msg_len
318 * is probably not set yet.
319 */
320
321 if (FIID_OBJ_PACKET_VALID (obj_lan_msg_hdr) < 0)
322 {
323 FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_msg_hdr);
324 return (-1);
325 }
326 if (FIID_OBJ_PACKET_VALID (obj_cmd) < 0)
327 {
328 FIID_OBJECT_ERROR_TO_ERRNO (obj_cmd);
329 return (-1);
330 }
331
332 if (FIID_OBJ_GET (obj_lan_session_hdr,
333 "authentication_type",
334 &val) < 0)
335 {
336 ERRNO_TRACE (errno);
337 return (-1);
338 }
339 authentication_type = val;
340
341 if (authentication_type != IPMI_AUTHENTICATION_TYPE_NONE
342 && authentication_type != IPMI_AUTHENTICATION_TYPE_MD2
343 && authentication_type != IPMI_AUTHENTICATION_TYPE_MD5
344 && authentication_type != IPMI_AUTHENTICATION_TYPE_STRAIGHT_PASSWORD_KEY)
345 {
346 SET_ERRNO (EINVAL);
347 return (-1);
348 }
349
350 /* no need for overflow checks, handled w/ _ipmi_lan_pkt_rq_min_size check */
351
352 required_len = _ipmi_lan_pkt_rq_min_size (authentication_type, obj_cmd);
353 if (pkt_len < required_len)
354 {
355 SET_ERRNO (EMSGSIZE);
356 return (-1);
357 }
358
359 if ((len = fiid_obj_get_all (obj_rmcp_hdr, pkt + indx, pkt_len - indx)) < 0)
360 {
361 FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcp_hdr);
362 goto cleanup;
363 }
364 indx += len;
365
366 if ((len = fiid_obj_get_block (obj_lan_session_hdr,
367 "authentication_type",
368 "session_id",
369 pkt + indx,
370 pkt_len - indx)) < 0)
371 {
372 FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_session_hdr);
373 goto cleanup;
374 }
375
376 indx += len;
377
378 /* authentication_code generated last. Save pointers for later calculation */
379 if (authentication_type != IPMI_AUTHENTICATION_TYPE_NONE)
380 {
381 authentication_code_field_ptr = (pkt + indx);
382 indx += IPMI_1_5_MAX_PASSWORD_LENGTH;
383 }
384
385 ipmi_msg_len_ptr = (pkt + indx);
386 if ((len = fiid_template_field_len_bytes (tmpl_lan_session_hdr, "ipmi_msg_len")) < 0)
387 {
388 ERRNO_TRACE (errno);
389 goto cleanup;
390 }
391 if (len != 1)
392 {
393 SET_ERRNO (EINVAL);
394 goto cleanup;
395 }
396 indx += len;
397
398 msg_data_ptr = (pkt + indx);
399
400 if ((len = fiid_obj_get_block (obj_lan_msg_hdr,
401 "rs_addr",
402 "checksum1",
403 pkt + indx,
404 pkt_len - indx)) < 0)
405 {
406 FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_msg_hdr);
407 goto cleanup;
408 }
409 indx += len;
410 msg_data_count += len;
411
412 checksum_data_ptr = (pkt + indx);
413
414 if ((len = fiid_obj_get_block (obj_lan_msg_hdr,
415 "rq_addr",
416 "rq_seq",
417 pkt + indx,
418 pkt_len - indx)) < 0)
419 {
420 FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_msg_hdr);
421 goto cleanup;
422 }
423 indx += len;
424 msg_data_count += len;
425 checksum_data_count += len;
426
427 if ((len = fiid_obj_get_all (obj_cmd, pkt + indx, pkt_len - indx)) < 0)
428 {
429 FIID_OBJECT_ERROR_TO_ERRNO (obj_cmd);
430 goto cleanup;
431 }
432 indx += len;
433 msg_data_count += len;
434 checksum_data_count += len;
435
436 if (!(obj_lan_msg_trlr = fiid_obj_create (tmpl_lan_msg_trlr)))
437 {
438 ERRNO_TRACE (errno);
439 goto cleanup;
440 }
441
442 checksum = ipmi_checksum (checksum_data_ptr, checksum_data_count);
443
444 if (fiid_obj_set_all (obj_lan_msg_trlr, &checksum, sizeof (checksum)) < 0)
445 {
446 FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_msg_trlr);
447 goto cleanup;
448 }
449
450 if ((len = fiid_obj_get_all (obj_lan_msg_trlr, pkt + indx, pkt_len - indx)) < 0)
451 {
452 FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_msg_trlr);
453 goto cleanup;
454 }
455 indx += len;
456 msg_data_count += len;
457
458 /* ipmi_msg_len done after message length is computed */
459 ipmi_msg_len = msg_data_count;
460 memcpy (ipmi_msg_len_ptr,
461 &ipmi_msg_len,
462 sizeof (ipmi_msg_len));
463
464 /* Auth code must be done last, some authentication like md2 and md5
465 * require all fields, including checksums, to be calculated
466 * beforehand
467 */
468 if (authentication_type != IPMI_AUTHENTICATION_TYPE_NONE)
469 {
470 int authentication_len;
471
472 /* clear out, might need empty buf */
473 memset (pwbuf, '\0', IPMI_1_5_MAX_PASSWORD_LENGTH);
474
475 if ((authentication_len = fiid_obj_field_len_bytes (obj_lan_session_hdr,
476 "authentication_code")) < 0)
477 {
478 FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_session_hdr);
479 goto cleanup;
480 }
481
482 if (authentication_len)
483 {
484 if (fiid_obj_get_data (obj_lan_session_hdr,
485 "authentication_code",
486 pwbuf,
487 IPMI_1_5_MAX_PASSWORD_LENGTH) < 0)
488 {
489 FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_session_hdr);
490 goto cleanup;
491 }
492
493 memcpy (authentication_code_field_ptr,
494 pwbuf,
495 IPMI_1_5_MAX_PASSWORD_LENGTH);
496 }
497 else
498 {
499 if (authentication_code_data)
500 memcpy (pwbuf,
501 authentication_code_data,
502 authentication_code_data_len);
503
504 if (authentication_type == IPMI_AUTHENTICATION_TYPE_STRAIGHT_PASSWORD_KEY)
505 {
506 memcpy (authentication_code_field_ptr,
507 pwbuf,
508 IPMI_1_5_MAX_PASSWORD_LENGTH);
509 }
510 else /* IPMI_AUTHENTICATION_TYPE_MD2 || IPMI_AUTHENTICATION_TYPE_MD5 */
511 {
512 uint8_t session_id_buf[1024];
513 uint8_t session_sequence_number_buf[1024];
514 int session_id_len, session_sequence_number_len;
515
516 if ((session_id_len = fiid_obj_get_data (obj_lan_session_hdr,
517 "session_id",
518 session_id_buf,
519 1024)) < 0)
520 {
521 FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_session_hdr);
522 goto cleanup;
523 }
524
525 if ((session_sequence_number_len = fiid_obj_get_data (obj_lan_session_hdr,
526 "session_sequence_number",
527 session_sequence_number_buf,
528 1024)) < 0)
529 {
530 FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_session_hdr);
531 goto cleanup;
532 }
533
534 if (authentication_type == IPMI_AUTHENTICATION_TYPE_MD2)
535 {
536 md2_t ctx;
537 uint8_t digest[MD2_DIGEST_LENGTH];
538
539 assert (IPMI_1_5_MAX_PASSWORD_LENGTH == MD2_DIGEST_LENGTH);
540
541 md2_init (&ctx);
542 md2_update_data (&ctx, pwbuf, IPMI_1_5_MAX_PASSWORD_LENGTH);
543 md2_update_data (&ctx, session_id_buf, session_id_len);
544 md2_update_data (&ctx, msg_data_ptr, msg_data_count);
545 md2_update_data (&ctx, session_sequence_number_buf, session_sequence_number_len);
546 md2_update_data (&ctx, pwbuf, IPMI_1_5_MAX_PASSWORD_LENGTH);
547 md2_finish (&ctx, digest, MD2_DIGEST_LENGTH);
548 md2_init (&ctx);
549
550 memcpy (authentication_code_field_ptr, digest, IPMI_1_5_MAX_PASSWORD_LENGTH);
551 }
552 else if (authentication_type == IPMI_AUTHENTICATION_TYPE_MD5)
553 {
554 md5_t ctx;
555 uint8_t digest[MD5_DIGEST_LENGTH];
556
557 assert (IPMI_1_5_MAX_PASSWORD_LENGTH == MD5_DIGEST_LENGTH);
558
559 md5_init (&ctx);
560 md5_update_data (&ctx, pwbuf, IPMI_1_5_MAX_PASSWORD_LENGTH);
561 md5_update_data (&ctx, session_id_buf, session_id_len);
562 md5_update_data (&ctx, msg_data_ptr, msg_data_count);
563 md5_update_data (&ctx, session_sequence_number_buf, session_sequence_number_len);
564 md5_update_data (&ctx, pwbuf, IPMI_1_5_MAX_PASSWORD_LENGTH);
565 md5_finish (&ctx, digest, MD5_DIGEST_LENGTH);
566 md5_init (&ctx);
567
568 memcpy (authentication_code_field_ptr, digest, IPMI_1_5_MAX_PASSWORD_LENGTH);
569 }
570 }
571 }
572 }
573
574 if (indx > INT_MAX)
575 {
576 SET_ERRNO (EMSGSIZE);
577 goto cleanup;
578 }
579
580 rv = indx;
581 cleanup:
582 if (rv < 0)
583 {
584 /* If plain password, pkt may contain it */
585 if (authentication_type == IPMI_AUTHENTICATION_TYPE_STRAIGHT_PASSWORD_KEY)
586 secure_memset (pkt, '\0', pkt_len);
587 }
588 fiid_obj_destroy (obj_lan_msg_trlr);
589 /* secure_memset because can contain password */
590 secure_memset (pwbuf, '\0', IPMI_1_5_MAX_PASSWORD_LENGTH);
591 return (rv);
592 }
593
594 /*
595 Complete IPMI LAN Response Packet
596 +----------------------+
597 | Session |
598 | RMCP |
599 | Message |
600 | Command |
601 | Completion Code |
602 | Data |
603 | Checksum |
604 +----------------------+
605 Optional Arguments : (pass NULL to ignore)
606 rmcp_hdr, session, msg, cmd and checksum
607 */
608
609 int
unassemble_ipmi_lan_pkt(const void * pkt,unsigned int pkt_len,fiid_obj_t obj_rmcp_hdr,fiid_obj_t obj_lan_session_hdr,fiid_obj_t obj_lan_msg_hdr,fiid_obj_t obj_cmd,fiid_obj_t obj_lan_msg_trlr,unsigned int flags)610 unassemble_ipmi_lan_pkt (const void *pkt,
611 unsigned int pkt_len,
612 fiid_obj_t obj_rmcp_hdr,
613 fiid_obj_t obj_lan_session_hdr,
614 fiid_obj_t obj_lan_msg_hdr,
615 fiid_obj_t obj_cmd,
616 fiid_obj_t obj_lan_msg_trlr,
617 unsigned int flags)
618 {
619 uint8_t authentication_type;
620 unsigned int indx = 0;
621 unsigned int obj_cmd_len;
622 int obj_lan_msg_trlr_len, len;
623 uint64_t val;
624 unsigned int flags_mask = (IPMI_INTERFACE_FLAGS_NO_LEGAL_CHECK);
625
626 if (!pkt
627 || !fiid_obj_valid (obj_rmcp_hdr)
628 || !fiid_obj_valid (obj_lan_session_hdr)
629 || !fiid_obj_valid (obj_lan_msg_hdr)
630 || !fiid_obj_valid (obj_cmd)
631 || !fiid_obj_valid (obj_lan_msg_trlr)
632 || (flags & ~flags_mask))
633 {
634 SET_ERRNO (EINVAL);
635 return (-1);
636 }
637
638 if (FIID_OBJ_TEMPLATE_COMPARE (obj_rmcp_hdr, tmpl_rmcp_hdr) < 0)
639 {
640 ERRNO_TRACE (errno);
641 return (-1);
642 }
643 if (FIID_OBJ_TEMPLATE_COMPARE (obj_lan_session_hdr, tmpl_lan_session_hdr) < 0)
644 {
645 ERRNO_TRACE (errno);
646 return (-1);
647 }
648 if (FIID_OBJ_TEMPLATE_COMPARE (obj_lan_msg_hdr, tmpl_lan_msg_hdr_rs) < 0)
649 {
650 ERRNO_TRACE (errno);
651 return (-1);
652 }
653 if (FIID_OBJ_TEMPLATE_COMPARE (obj_lan_msg_trlr, tmpl_lan_msg_trlr) < 0)
654 {
655 ERRNO_TRACE (errno);
656 return (-1);
657 }
658
659 indx = 0;
660 if (fiid_obj_clear (obj_rmcp_hdr) < 0)
661 {
662 FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcp_hdr);
663 return (-1);
664 }
665
666 if (fiid_obj_clear (obj_lan_session_hdr) < 0)
667 {
668 FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_session_hdr);
669 return (-1);
670 }
671
672 if (fiid_obj_clear (obj_lan_msg_hdr) < 0)
673 {
674 FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_msg_hdr);
675 return (-1);
676 }
677
678 if (fiid_obj_clear (obj_cmd) < 0)
679 {
680 FIID_OBJECT_ERROR_TO_ERRNO (obj_cmd);
681 return (-1);
682 }
683
684 if (fiid_obj_clear (obj_lan_msg_trlr) < 0)
685 {
686 FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_msg_trlr);
687 return (-1);
688 }
689
690 if ((len = fiid_obj_set_all (obj_rmcp_hdr, pkt + indx, pkt_len - indx)) < 0)
691 {
692 FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcp_hdr);
693 return (-1);
694 }
695 indx += len;
696
697 if (pkt_len <= indx)
698 {
699 /* cannot parse packet */
700 ERR_TRACE ("malformed packet", EINVAL);
701 return (0);
702 }
703
704 if ((len = fiid_obj_set_block (obj_lan_session_hdr,
705 "authentication_type",
706 "session_id",
707 pkt + indx,
708 pkt_len - indx)) < 0)
709 {
710 FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_session_hdr);
711 return (-1);
712 }
713 indx += len;
714
715 if (FIID_OBJ_GET (obj_lan_session_hdr,
716 "authentication_type",
717 &val) < 0)
718 {
719 FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_session_hdr);
720 return (-1);
721 }
722 authentication_type = val;
723
724 if (!IPMI_1_5_AUTHENTICATION_TYPE_VALID (authentication_type))
725 {
726 /* cannot parse packet */
727 ERR_TRACE ("malformed packet", EINVAL);
728 return (0);
729 }
730
731 if (authentication_type != IPMI_AUTHENTICATION_TYPE_NONE)
732 {
733 if ((len = fiid_obj_set_data (obj_lan_session_hdr,
734 "authentication_code",
735 pkt + indx,
736 pkt_len - indx)) < 0)
737 {
738 FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_session_hdr);
739 return (-1);
740 }
741 indx += len;
742
743 if (pkt_len <= indx)
744 {
745 /* cannot parse packet */
746 ERR_TRACE ("malformed packet", EINVAL);
747 return (0);
748 }
749 }
750
751 if ((len = fiid_obj_set_data (obj_lan_session_hdr,
752 "ipmi_msg_len",
753 pkt + indx,
754 pkt_len - indx)) < 0)
755 {
756 FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_session_hdr);
757 return (-1);
758 }
759 indx += len;
760
761 if (pkt_len <= indx)
762 {
763 /* cannot parse packet */
764 ERR_TRACE ("malformed packet", EINVAL);
765 return (0);
766 }
767
768 if ((len = fiid_obj_set_all (obj_lan_msg_hdr, pkt + indx, pkt_len - indx)) < 0)
769 {
770 FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_msg_hdr);
771 return (-1);
772 }
773 indx += len;
774
775 if (pkt_len <= indx)
776 {
777 /* cannot parse packet */
778 ERR_TRACE ("malformed packet", EINVAL);
779 return (0);
780 }
781
782 if ((obj_lan_msg_trlr_len = fiid_template_len_bytes (tmpl_lan_msg_trlr)) < 0)
783 {
784 ERRNO_TRACE (errno);
785 return (-1);
786 }
787
788 if ((pkt_len - indx) <= obj_lan_msg_trlr_len)
789 {
790 /* cannot parse packet */
791 ERR_TRACE ("malformed packet", EINVAL);
792 return (0);
793 }
794
795 obj_cmd_len = (pkt_len - indx) - obj_lan_msg_trlr_len;
796
797 if ((len = fiid_obj_set_all (obj_cmd, pkt + indx, obj_cmd_len)) < 0)
798 {
799 FIID_OBJECT_ERROR_TO_ERRNO (obj_cmd);
800 return (-1);
801 }
802 indx += len;
803
804 if (pkt_len <= indx)
805 {
806 /* cannot parse packet */
807 ERR_TRACE ("malformed packet", EINVAL);
808 return (0);
809 }
810
811 if ((len = fiid_obj_set_all (obj_lan_msg_trlr, pkt + indx, pkt_len - indx)) < 0)
812 {
813 FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_msg_trlr);
814 return (-1);
815 }
816 indx += len;
817
818 if (FIID_OBJ_PACKET_VALID (obj_rmcp_hdr) == 1
819 && FIID_OBJ_PACKET_VALID (obj_lan_session_hdr) == 1
820 && FIID_OBJ_PACKET_VALID (obj_lan_msg_hdr) == 1
821 && ((flags & IPMI_INTERFACE_FLAGS_NO_LEGAL_CHECK) || FIID_OBJ_PACKET_SUFFICIENT (obj_cmd) == 1)
822 && FIID_OBJ_PACKET_VALID (obj_lan_msg_trlr) == 1)
823 return (1);
824
825 return (0);
826 }
827
828 ssize_t
ipmi_lan_sendto(int s,const void * buf,size_t len,int flags,const struct sockaddr * to,socklen_t tolen)829 ipmi_lan_sendto (int s,
830 const void *buf,
831 size_t len,
832 int flags,
833 const struct sockaddr *to,
834 socklen_t tolen)
835 {
836 /* achu: Specification table 13-8, indicates legacy padding for IPMI 1.5, but
837 * it appears it is specific to Ethernet 10/100 lan chips.
838 *
839 * It is so legacy at this point it is probably not worth providing.
840 * In addition, it is difficult to calculate if a pad is necessary
841 * b/c it appears the pad should be for the ethernet frame, not the
842 * IP packet.
843 *
844 * Why not just remove this function? Leave just in case a legacy
845 * pad situation pops up and we gotta implement something.
846 */
847 return (ipmi_network_sendto (s, buf, len, flags, to, tolen));
848 }
849
850 ssize_t
ipmi_lan_recvfrom(int s,void * buf,size_t len,int flags,struct sockaddr * from,socklen_t * fromlen)851 ipmi_lan_recvfrom (int s,
852 void *buf,
853 size_t len,
854 int flags,
855 struct sockaddr *from,
856 socklen_t *fromlen)
857 {
858 return (ipmi_network_recvfrom (s, buf, len, flags, from, fromlen));
859 }
860
861