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