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 /* 2's complement checksum of preceding bytes in the connection header
20    or between the previous checksum. 8-bit checksum algorithm:
21    Initialize checksum to 0.
22    For each byte, checksum = (checksum + byte) modulo 256. Then find
23    1's compliment of checksum and add one to it.
24    To verify add all the bytes and the checksum and then % 256 should
25    yield 0.
26 */
27 
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif /* HAVE_CONFIG_H */
31 
32 #include <stdio.h>
33 #include <stdlib.h>
34 #ifdef STDC_HEADERS
35 #include <string.h>
36 #endif /* STDC_HEADERS */
37 #include <errno.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #if HAVE_FCNTL_H
41 #include <fcntl.h>
42 #endif /* HAVE_FCNTL_H */
43 #if HAVE_UNISTD_H
44 #include <unistd.h>
45 #endif /* HAVE_UNISTD_H */
46 
47 #include "freeipmi/util/ipmi-outofband-util.h"
48 #include "freeipmi/fiid/fiid.h"
49 #include "freeipmi/cmds/ipmi-messaging-support-cmds.h"
50 #include "freeipmi/interface/ipmi-rmcpplus-interface.h"
51 #include "freeipmi/interface/rmcp-interface.h"
52 #include "freeipmi/spec/ipmi-authentication-type-spec.h"
53 #include "freeipmi/spec/ipmi-privilege-level-spec.h"
54 
55 #include "libcommon/ipmi-fiid-util.h"
56 #include "libcommon/ipmi-trace.h"
57 
58 #include "freeipmi-portability.h"
59 
60 #define IPMI_SEQUENCE_NUMBER_MAX            0xFFFFFFFF
61 #define IPMI_SEQUENCE_NUMBER_WINDOW_DEFAULT          8
62 #define IPMI_SEQUENCE_NUMBER_WINDOW_MAX             32
63 #define IPMI_SEQUENCE_NUMBER_WINDOW_MIN              1
64 
65 int
ipmi_is_ipmi_1_5_packet(const void * pkt,unsigned int pkt_len)66 ipmi_is_ipmi_1_5_packet (const void *pkt, unsigned int pkt_len)
67 {
68   int rmcp_hdr_len;
69   uint8_t auth_type;
70 
71   if ((rmcp_hdr_len = fiid_template_len_bytes (tmpl_rmcp_hdr)) < 0)
72     {
73       ERRNO_TRACE (errno);
74       return (-1);
75     }
76 
77   if (pkt_len <= rmcp_hdr_len)
78     {
79       SET_ERRNO (EINVAL);
80       return (-1);
81     }
82 
83   auth_type = *((uint8_t *)(pkt + rmcp_hdr_len));
84   auth_type &= 0x0F;
85   return ((auth_type != IPMI_AUTHENTICATION_TYPE_RMCPPLUS) ? 1 : 0);
86 }
87 
88 int
ipmi_is_ipmi_2_0_packet(const void * pkt,unsigned int pkt_len)89 ipmi_is_ipmi_2_0_packet (const void *pkt, unsigned int pkt_len)
90 {
91   int rmcp_hdr_len;
92   uint8_t auth_type;
93 
94   if ((rmcp_hdr_len = fiid_template_len_bytes (tmpl_rmcp_hdr)) < 0)
95     {
96       ERRNO_TRACE (errno);
97       return (-1);
98     }
99 
100   if (pkt_len <= rmcp_hdr_len)
101     {
102       SET_ERRNO (EINVAL);
103       return (-1);
104     }
105 
106   auth_type = *((uint8_t *)(pkt + rmcp_hdr_len));
107   auth_type &= 0x0F;
108   return ((auth_type == IPMI_AUTHENTICATION_TYPE_RMCPPLUS) ? 1 : 0);
109 }
110 
111 int
ipmi_check_session_sequence_number_1_5_init(uint32_t * highest_received_sequence_number,uint32_t * previously_received_list)112 ipmi_check_session_sequence_number_1_5_init (uint32_t *highest_received_sequence_number,
113                                              uint32_t *previously_received_list)
114 {
115   if (!highest_received_sequence_number
116       || !previously_received_list)
117     {
118       SET_ERRNO (EINVAL);
119       return (-1);
120     }
121 
122   (*highest_received_sequence_number) = 0;
123   (*previously_received_list) = 0xFF;
124 
125   return (0);
126 }
127 
128 int
ipmi_check_session_sequence_number_2_0_init(uint32_t * highest_received_sequence_number,uint32_t * previously_received_list)129 ipmi_check_session_sequence_number_2_0_init (uint32_t *highest_received_sequence_number,
130                                              uint32_t *previously_received_list)
131 {
132   if (!highest_received_sequence_number
133       || !previously_received_list)
134     {
135       SET_ERRNO (EINVAL);
136       return (-1);
137     }
138 
139   (*highest_received_sequence_number) = 0;
140   (*previously_received_list) = 0xFF;
141 
142   return (0);
143 }
144 
145 static int
_check_session_sequence_number(uint32_t session_sequence_number,uint32_t * highest_received_sequence_number,uint32_t * previously_received_list,unsigned int sequence_number_window,int ipmi_2_0_flag)146 _check_session_sequence_number (uint32_t session_sequence_number,
147                                 uint32_t *highest_received_sequence_number,
148                                 uint32_t *previously_received_list,
149                                 unsigned int sequence_number_window,
150                                 int ipmi_2_0_flag)
151 {
152   uint32_t shift_num, wrap_val;
153 
154   if (!highest_received_sequence_number
155       || !previously_received_list)
156     {
157       SET_ERRNO (EINVAL);
158       return (-1);
159     }
160 
161   if (sequence_number_window > IPMI_SEQUENCE_NUMBER_WINDOW_MAX)
162     {
163       SET_ERRNO (EINVAL);
164       return (-1);
165     }
166 
167   if (!sequence_number_window)
168     sequence_number_window = IPMI_SEQUENCE_NUMBER_WINDOW_DEFAULT;
169 
170   /* achu: This algorithm is more or less from Appendix A of the IPMI
171    * spec.  I know that technically I could remove a lot of code here
172    * if I just let unsigned ints wrap around.  I dunno, I like to see
173    * all of the code actually written out b/c it makes more sense to
174    * the casual code reviewer.  Maybe I'll change it later.
175    */
176 
177   /* Drop duplicate packet */
178   if (session_sequence_number == (*highest_received_sequence_number))
179     return (0);
180 
181   /* In IPMI 2.0, sequence number 0 is special, and shouldn't happen */
182   if (ipmi_2_0_flag && !session_sequence_number)
183     return (0);
184 
185   /* Check if sequence number is greater than highest received and is
186    * within range
187    */
188   if ((*highest_received_sequence_number) > (IPMI_SEQUENCE_NUMBER_MAX - IPMI_SEQUENCE_NUMBER_WINDOW_DEFAULT))
189     {
190       wrap_val = IPMI_SEQUENCE_NUMBER_WINDOW_DEFAULT - (IPMI_SEQUENCE_NUMBER_MAX - (*highest_received_sequence_number)) - 1;
191 
192       /* In IPMI 2.0, sequence number 0 isn't possible, so adjust wrap_val */
193       if (ipmi_2_0_flag)
194         wrap_val++;
195 
196       if ((session_sequence_number > (*highest_received_sequence_number))
197           || (session_sequence_number <= wrap_val))
198         {
199           if (session_sequence_number > (*highest_received_sequence_number) && session_sequence_number <= IPMI_SEQUENCE_NUMBER_MAX)
200             shift_num = session_sequence_number - (*highest_received_sequence_number);
201           else
202             {
203               /* IPMI 2.0 Special Case b/c 0 isn't a legit sequence number */
204               if (ipmi_2_0_flag)
205                 shift_num = session_sequence_number + (IPMI_SEQUENCE_NUMBER_MAX - (*highest_received_sequence_number));
206               else
207                 shift_num = session_sequence_number + (IPMI_SEQUENCE_NUMBER_MAX - (*highest_received_sequence_number)) + 1;
208             }
209 
210           (*highest_received_sequence_number) = session_sequence_number;
211           (*previously_received_list) <<= shift_num;
212           (*previously_received_list) |= (0x1 << (shift_num - 1));
213           return (1);
214         }
215     }
216   else
217     {
218       if (session_sequence_number > (*highest_received_sequence_number)
219           && (session_sequence_number - (*highest_received_sequence_number)) <= IPMI_SEQUENCE_NUMBER_WINDOW_DEFAULT)
220         {
221           shift_num = (session_sequence_number - (*highest_received_sequence_number));
222           (*highest_received_sequence_number) = session_sequence_number;
223           (*previously_received_list) <<= shift_num;
224           (*previously_received_list) |= (0x1 << (shift_num - 1));
225           return (1);
226         }
227     }
228 
229   /* Check if sequence number is lower than highest received, is
230    * within range, and hasn't been seen yet
231    */
232   if ((*highest_received_sequence_number) < IPMI_SEQUENCE_NUMBER_WINDOW_DEFAULT)
233     {
234       wrap_val = IPMI_SEQUENCE_NUMBER_MAX - (IPMI_SEQUENCE_NUMBER_WINDOW_DEFAULT - (*highest_received_sequence_number)) + 1;
235 
236       /* In IPMI 2.0, sequence number 0 isn't possible, so adjust wrap_val */
237       if (ipmi_2_0_flag)
238         wrap_val--;
239 
240       if (session_sequence_number < (*highest_received_sequence_number) || session_sequence_number >= wrap_val)
241         {
242           if (session_sequence_number > (*highest_received_sequence_number) && session_sequence_number <= IPMI_SEQUENCE_NUMBER_MAX)
243             {
244               /* IPMI 2.0 Special Case b/c 0 isn't a legit sequence number */
245               if (ipmi_2_0_flag)
246                 shift_num = (*highest_received_sequence_number) + (IPMI_SEQUENCE_NUMBER_MAX - session_sequence_number);
247               else
248                 shift_num = (*highest_received_sequence_number) + (IPMI_SEQUENCE_NUMBER_MAX - session_sequence_number) + 1;
249             }
250           else
251             shift_num = (*highest_received_sequence_number) - session_sequence_number;
252 
253           /* Duplicate packet check*/
254           if ((*previously_received_list) & (0x1 << (shift_num - 1)))
255             return (0);
256 
257           (*previously_received_list) |= (0x1 << (shift_num - 1));
258           return (1);
259         }
260     }
261   else
262     {
263       if (session_sequence_number < (*highest_received_sequence_number)
264           && session_sequence_number >= ((*highest_received_sequence_number) - IPMI_SEQUENCE_NUMBER_WINDOW_DEFAULT))
265         {
266           shift_num = (*highest_received_sequence_number) - session_sequence_number;
267 
268           /* Duplicate packet check*/
269           if ((*previously_received_list) & (0x1 << (shift_num - 1)))
270             return (0);
271 
272           (*previously_received_list) |= (0x1 << (shift_num - 1));
273           return (1);
274         }
275     }
276 
277   return (0);
278 }
279 
280 int
ipmi_check_session_sequence_number_1_5(uint32_t session_sequence_number,uint32_t * highest_received_sequence_number,uint32_t * previously_received_list,unsigned int sequence_number_window)281 ipmi_check_session_sequence_number_1_5 (uint32_t session_sequence_number,
282                                         uint32_t *highest_received_sequence_number,
283                                         uint32_t *previously_received_list,
284                                         unsigned int sequence_number_window)
285 {
286   return (_check_session_sequence_number (session_sequence_number,
287                                           highest_received_sequence_number,
288                                           previously_received_list,
289                                           sequence_number_window,
290                                           0));
291 }
292 
293 int
ipmi_check_session_sequence_number_2_0(uint32_t session_sequence_number,uint32_t * highest_received_sequence_number,uint32_t * previously_received_list,unsigned int sequence_number_window)294 ipmi_check_session_sequence_number_2_0 (uint32_t session_sequence_number,
295                                         uint32_t *highest_received_sequence_number,
296                                         uint32_t *previously_received_list,
297                                         unsigned int sequence_number_window)
298 {
299   return (_check_session_sequence_number (session_sequence_number,
300                                           highest_received_sequence_number,
301                                           previously_received_list,
302                                           sequence_number_window,
303                                           1));
304 }
305 
306 int
ipmi_check_authentication_capabilities_authentication_type(uint8_t authentication_type,fiid_obj_t obj_cmd)307 ipmi_check_authentication_capabilities_authentication_type (uint8_t authentication_type,
308                                                             fiid_obj_t obj_cmd)
309 {
310   uint8_t supported_authentication_type = 0;
311   uint64_t val;
312 
313   if (!IPMI_1_5_AUTHENTICATION_TYPE_VALID (authentication_type)
314       || !fiid_obj_valid (obj_cmd))
315     {
316       SET_ERRNO (EINVAL);
317       return (-1);
318     }
319 
320   if (FIID_OBJ_TEMPLATE_COMPARE (obj_cmd, tmpl_cmd_get_channel_authentication_capabilities_rs) < 0)
321     {
322       SET_ERRNO (EINVAL);
323       return (-1);
324     }
325 
326   switch (authentication_type)
327     {
328     case IPMI_AUTHENTICATION_TYPE_NONE:
329       if (FIID_OBJ_GET (obj_cmd,
330                         "authentication_type.none",
331                         &val) < 0)
332         {
333           FIID_OBJECT_ERROR_TO_ERRNO (obj_cmd);
334           return (-1);
335         }
336       supported_authentication_type = val;
337       break;
338     case IPMI_AUTHENTICATION_TYPE_MD2:
339       if (FIID_OBJ_GET (obj_cmd,
340                         "authentication_type.md2",
341                         &val) < 0)
342         {
343           FIID_OBJECT_ERROR_TO_ERRNO (obj_cmd);
344           return (-1);
345         }
346       supported_authentication_type = val;
347       break;
348     case IPMI_AUTHENTICATION_TYPE_MD5:
349       if (FIID_OBJ_GET (obj_cmd,
350                         "authentication_type.md5",
351                         &val) < 0)
352         {
353           FIID_OBJECT_ERROR_TO_ERRNO (obj_cmd);
354           return (-1);
355         }
356       supported_authentication_type = val;
357       break;
358     case IPMI_AUTHENTICATION_TYPE_STRAIGHT_PASSWORD_KEY:
359       if (FIID_OBJ_GET (obj_cmd,
360                         "authentication_type.straight_password_key",
361                         &val) < 0)
362         {
363           FIID_OBJECT_ERROR_TO_ERRNO (obj_cmd);
364           return (-1);
365         }
366       supported_authentication_type = val;
367       break;
368     case IPMI_AUTHENTICATION_TYPE_OEM_PROP:
369       if (FIID_OBJ_GET (obj_cmd,
370                         "authentication_type.oem_prop",
371                         &val) < 0)
372         {
373           FIID_OBJECT_ERROR_TO_ERRNO (obj_cmd);
374           return (-1);
375         }
376       supported_authentication_type = val;
377       break;
378     }
379 
380   if (supported_authentication_type)
381     return (1);
382 
383   return (0);
384 }
385 
386 int
ipmi_check_authentication_capabilities_username(const char * username,const char * password,fiid_obj_t obj_cmd)387 ipmi_check_authentication_capabilities_username (const char *username,
388                                                  const char *password,
389                                                  fiid_obj_t obj_cmd)
390 {
391   uint8_t authentication_status_anonymous_login;
392   uint8_t authentication_status_null_username;
393   uint8_t authentication_status_non_null_username;
394   uint64_t val;
395 
396   if (!fiid_obj_valid (obj_cmd))
397     {
398       SET_ERRNO (EINVAL);
399       return (-1);
400     }
401 
402   if (FIID_OBJ_TEMPLATE_COMPARE (obj_cmd, tmpl_cmd_get_channel_authentication_capabilities_rs) < 0)
403     {
404       SET_ERRNO (EINVAL);
405       return (-1);
406     }
407 
408   if (FIID_OBJ_GET (obj_cmd,
409                     "authentication_status.anonymous_login",
410                     &val) < 0)
411     {
412       FIID_OBJECT_ERROR_TO_ERRNO (obj_cmd);
413       return (-1);
414     }
415   authentication_status_anonymous_login = val;
416 
417   if (FIID_OBJ_GET (obj_cmd,
418                     "authentication_status.null_username",
419                     &val) < 0)
420     {
421       FIID_OBJECT_ERROR_TO_ERRNO (obj_cmd);
422       return (-1);
423     }
424   authentication_status_null_username = val;
425 
426   if (FIID_OBJ_GET (obj_cmd,
427                     "authentication_status.non_null_username",
428                     &val) < 0)
429     {
430       FIID_OBJECT_ERROR_TO_ERRNO (obj_cmd);
431       return (-1);
432     }
433   authentication_status_non_null_username = val;
434 
435   if ((!username && !password && !authentication_status_anonymous_login)
436       || (!username && password && !authentication_status_null_username)
437       || (username  && !authentication_status_non_null_username))
438     return (0);
439 
440   return (1);
441 }
442 
443 int
ipmi_check_authentication_capabilities_ipmi_2_0(fiid_obj_t obj_cmd)444 ipmi_check_authentication_capabilities_ipmi_2_0 (fiid_obj_t obj_cmd)
445 {
446   uint8_t ipmi_v20_extended_capabilities_available;
447   uint8_t channel_supports_ipmi_v20_connections;
448   uint64_t val;
449 
450   if (!fiid_obj_valid (obj_cmd))
451     {
452       SET_ERRNO (EINVAL);
453       return (-1);
454     }
455 
456   if (FIID_OBJ_TEMPLATE_COMPARE (obj_cmd, tmpl_cmd_get_channel_authentication_capabilities_rs) < 0)
457     {
458       SET_ERRNO (EINVAL);
459       return (-1);
460     }
461 
462   if (FIID_OBJ_GET (obj_cmd,
463                     "authentication_type.ipmi_v2.0_extended_capabilities_available",
464                     &val) < 0)
465     {
466       FIID_OBJECT_ERROR_TO_ERRNO (obj_cmd);
467       return (-1);
468     }
469   ipmi_v20_extended_capabilities_available = val;
470 
471   if (FIID_OBJ_GET (obj_cmd,
472                     "channel_supports_ipmi_v2.0_connections",
473                     &val) < 0)
474     {
475       FIID_OBJECT_ERROR_TO_ERRNO (obj_cmd);
476       return (-1);
477     }
478   channel_supports_ipmi_v20_connections = val;
479 
480   if (!ipmi_v20_extended_capabilities_available
481       || !channel_supports_ipmi_v20_connections)
482     return (0);
483 
484   return (1);
485 }
486 
487 int
ipmi_check_authentication_capabilities_k_g(const void * k_g,fiid_obj_t obj_cmd)488 ipmi_check_authentication_capabilities_k_g (const void *k_g,
489                                             fiid_obj_t obj_cmd)
490 {
491   uint8_t authentication_status_k_g;
492   uint64_t val;
493 
494   if (!fiid_obj_valid (obj_cmd))
495     {
496       SET_ERRNO (EINVAL);
497       return (-1);
498     }
499 
500   if (FIID_OBJ_TEMPLATE_COMPARE (obj_cmd, tmpl_cmd_get_channel_authentication_capabilities_rs) < 0)
501     {
502       SET_ERRNO (EINVAL);
503       return (-1);
504     }
505 
506   if (FIID_OBJ_GET (obj_cmd,
507                     "authentication_status.k_g",
508                     &val) < 0)
509     {
510       FIID_OBJECT_ERROR_TO_ERRNO (obj_cmd);
511       return (-1);
512     }
513   authentication_status_k_g = val;
514 
515   if ((!k_g && authentication_status_k_g)
516       || (k_g && !authentication_status_k_g))
517     return (0);
518 
519   return (1);
520 }
521 
522 int
ipmi_check_open_session_maximum_privilege(uint8_t privilege_level,fiid_obj_t obj_cmd)523 ipmi_check_open_session_maximum_privilege (uint8_t privilege_level,
524                                            fiid_obj_t obj_cmd)
525 {
526   uint8_t maximum_privilege_level;
527   uint64_t val;
528 
529   if (!IPMI_PRIVILEGE_LEVEL_VALID (privilege_level)
530       || !fiid_obj_valid (obj_cmd))
531     {
532       SET_ERRNO (EINVAL);
533       return (-1);
534     }
535 
536   if (FIID_OBJ_TEMPLATE_COMPARE (obj_cmd, tmpl_rmcpplus_open_session_response) < 0)
537     {
538       SET_ERRNO (EINVAL);
539       return (-1);
540     }
541 
542   if (FIID_OBJ_GET (obj_cmd,
543                     "maximum_privilege_level",
544                     &val) < 0)
545     {
546       FIID_OBJECT_ERROR_TO_ERRNO (obj_cmd);
547       return (-1);
548     }
549   maximum_privilege_level = val;
550 
551   if (privilege_level == IPMI_PRIVILEGE_LEVEL_USER
552       && (maximum_privilege_level == IPMI_PRIVILEGE_LEVEL_USER
553           || maximum_privilege_level == IPMI_PRIVILEGE_LEVEL_OPERATOR
554           || maximum_privilege_level == IPMI_PRIVILEGE_LEVEL_ADMIN
555           || maximum_privilege_level == IPMI_PRIVILEGE_LEVEL_OEM))
556     return (1);
557   else if (privilege_level == IPMI_PRIVILEGE_LEVEL_OPERATOR
558            && (maximum_privilege_level == IPMI_PRIVILEGE_LEVEL_OPERATOR
559                    || maximum_privilege_level == IPMI_PRIVILEGE_LEVEL_ADMIN
560                || maximum_privilege_level == IPMI_PRIVILEGE_LEVEL_OEM))
561     return (1);
562   else if (privilege_level == IPMI_PRIVILEGE_LEVEL_ADMIN
563            && (maximum_privilege_level == IPMI_PRIVILEGE_LEVEL_ADMIN
564                || maximum_privilege_level == IPMI_PRIVILEGE_LEVEL_OEM))
565     return (1);
566   else if (privilege_level == IPMI_PRIVILEGE_LEVEL_OEM
567            && maximum_privilege_level == IPMI_PRIVILEGE_LEVEL_OEM)
568     return (1);
569 
570   return (0);
571 }
572