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