xref: /openbmc/ipmitool/lib/helper.c (revision 89e9e634)
1 /*
2  * Copyright (c) 2003 Sun Microsystems, Inc.  All Rights Reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * Redistribution of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *
11  * Redistribution in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  *
15  * Neither the name of Sun Microsystems, Inc. or the names of
16  * contributors may be used to endorse or promote products derived
17  * from this software without specific prior written permission.
18  *
19  * This software is provided "AS IS," without a warranty of any kind.
20  * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
21  * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
22  * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
23  * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
24  * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
25  * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.  IN NO EVENT WILL
26  * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
27  * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
28  * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
29  * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
30  * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
31  */
32 #define _POSIX_SOURCE
33 
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <sys/ioctl.h>  /* For TIOCNOTTY */
37 
38 #include <stdlib.h>
39 #include <stdint.h>
40 #include <stdio.h>
41 #include <inttypes.h>
42 #include <signal.h>
43 #include <string.h>
44 #include <strings.h>
45 #include <unistd.h>
46 #include <fcntl.h>
47 #include <errno.h>
48 #include <assert.h>
49 
50 #if HAVE_CONFIG_H
51 # include <config.h>
52 #endif
53 
54 #ifdef HAVE_PATHS_H
55 # include <paths.h>
56 #else
57 # define _PATH_VARRUN "/var/run/"
58 #endif
59 
60 #include <ipmitool/ipmi.h>
61 #include <ipmitool/ipmi_intf.h>
62 #include <ipmitool/helper.h>
63 #include <ipmitool/log.h>
64 
65 extern int verbose;
66 
67 uint32_t buf2long(uint8_t * buf)
68 {
69 	return (uint32_t)(buf[3] << 24 | buf[2] << 16 | buf[1] << 8 | buf[0]);
70 }
71 
72 uint16_t buf2short(uint8_t * buf)
73 {
74 	return (uint16_t)(buf[1] << 8 | buf[0]);
75 }
76 
77 const char * buf2str(uint8_t * buf, int len)
78 {
79 	static char str[2049];
80 	int i;
81 
82 	if (len <= 0 || len > 1024)
83 		return NULL;
84 
85 	memset(str, 0, 2049);
86 
87 	for (i=0; i<len; i++)
88 		sprintf(str+i+i, "%2.2x", buf[i]);
89 
90 	str[len*2] = '\0';
91 
92 	return (const char *)str;
93 }
94 
95 void printbuf(const uint8_t * buf, int len, const char * desc)
96 {
97 	int i;
98 
99 	if (len <= 0)
100 		return;
101 
102 	if (verbose < 1)
103 		return;
104 
105 	fprintf(stderr, "%s (%d bytes)\n", desc, len);
106 	for (i=0; i<len; i++) {
107 		if (((i%16) == 0) && (i != 0))
108 			fprintf(stderr, "\n");
109 		fprintf(stderr, " %2.2x", buf[i]);
110 	}
111 	fprintf(stderr, "\n");
112 }
113 
114 const char * val2str(uint16_t val, const struct valstr *vs)
115 {
116 	static char un_str[32];
117 	int i;
118 
119 	for (i = 0; vs[i].str != NULL; i++) {
120 		if (vs[i].val == val)
121 			return vs[i].str;
122 	}
123 
124 	memset(un_str, 0, 32);
125 	snprintf(un_str, 32, "Unknown (0x%02X)", val);
126 
127 	return un_str;
128 }
129 
130 const char * oemval2str(uint32_t oem, uint16_t val,
131                                              const struct oemvalstr *vs)
132 {
133 	static char un_str[32];
134 	int i;
135 
136 	for (i = 0; vs[i].oem != 0xffffff &&  vs[i].str != NULL; i++) {
137 		/* FIXME: for now on we assume PICMG capability on all IANAs */
138 		if ( (vs[i].oem == oem || vs[i].oem == IPMI_OEM_PICMG) &&
139 				vs[i].val == val ) {
140 			return vs[i].str;
141 		}
142 	}
143 
144 	memset(un_str, 0, 32);
145 	snprintf(un_str, 32, "Unknown (0x%X)", val);
146 
147 	return un_str;
148 }
149 
150 /* str2double - safely convert string to double
151  *
152  * @str: source string to convert from
153  * @double_ptr: pointer where to store result
154  *
155  * returns zero on success
156  * returns (-1) if one of args is NULL, (-2) invalid input, (-3) for *flow
157  */
158 int str2double(const char * str, double * double_ptr)
159 {
160 	char * end_ptr = 0;
161 	if (!str || !double_ptr)
162 		return (-1);
163 
164 	*double_ptr = 0;
165 	errno = 0;
166 	*double_ptr = strtod(str, &end_ptr);
167 
168 	if (*end_ptr != '\0')
169 		return (-2);
170 
171 	if (errno != 0)
172 		return (-3);
173 
174 	return 0;
175 } /* str2double(...) */
176 
177 /* str2long - safely convert string to int64_t
178  *
179  * @str: source string to convert from
180  * @lng_ptr: pointer where to store result
181  *
182  * returns zero on success
183  * returns (-1) if one of args is NULL, (-2) invalid input, (-3) for *flow
184  */
185 int str2long(const char * str, int64_t * lng_ptr)
186 {
187 	char * end_ptr = 0;
188 	if (!str || !lng_ptr)
189 		return (-1);
190 
191 	*lng_ptr = 0;
192 	errno = 0;
193 	*lng_ptr = strtol(str, &end_ptr, 0);
194 
195 	if (*end_ptr != '\0')
196 		return (-2);
197 
198 	if (errno != 0)
199 		return (-3);
200 
201 	return 0;
202 } /* str2long(...) */
203 
204 /* str2ulong - safely convert string to uint64_t
205  *
206  * @str: source string to convert from
207  * @ulng_ptr: pointer where to store result
208  *
209  * returns zero on success
210  * returns (-1) if one of args is NULL, (-2) invalid input, (-3) for *flow
211  */
212 int str2ulong(const char * str, uint64_t * ulng_ptr)
213 {
214 	char * end_ptr = 0;
215 	if (!str || !ulng_ptr)
216 		return (-1);
217 
218 	*ulng_ptr = 0;
219 	errno = 0;
220 	*ulng_ptr = strtoul(str, &end_ptr, 0);
221 
222 	if (*end_ptr != '\0')
223 		return (-2);
224 
225 	if (errno != 0)
226 		return (-3);
227 
228 	return 0;
229 } /* str2ulong(...) */
230 
231 /* str2int - safely convert string to int32_t
232  *
233  * @str: source string to convert from
234  * @int_ptr: pointer where to store result
235  *
236  * returns zero on success
237  * returns (-1) if one of args is NULL, (-2) invalid input, (-3) for *flow
238  */
239 int str2int(const char * str, int32_t * int_ptr)
240 {
241 	int rc = 0;
242 	int64_t arg_long = 0;
243 	if (!str || !int_ptr)
244 		return (-1);
245 
246 	if ( (rc = str2long(str, &arg_long)) != 0 ) {
247 		*int_ptr = 0;
248 		return rc;
249 	}
250 
251 	if (arg_long < INT32_MIN || arg_long > INT32_MAX)
252 		return (-3);
253 
254 	*int_ptr = (int32_t)arg_long;
255 	return 0;
256 } /* str2int(...) */
257 
258 /* str2uint - safely convert string to uint32_t
259  *
260  * @str: source string to convert from
261  * @uint_ptr: pointer where to store result
262  *
263  * returns zero on success
264  * returns (-1) if one of args is NULL, (-2) invalid input, (-3) for *flow
265  */
266 int str2uint(const char * str, uint32_t * uint_ptr)
267 {
268 	int rc = 0;
269 	uint64_t arg_ulong = 0;
270 	if (!str || !uint_ptr)
271 		return (-1);
272 
273 	if ( (rc = str2ulong(str, &arg_ulong)) != 0) {
274 		*uint_ptr = 0;
275 		return rc;
276 	}
277 
278 	if (arg_ulong > UINT32_MAX)
279 		return (-3);
280 
281 	*uint_ptr = (uint32_t)arg_ulong;
282 	return 0;
283 } /* str2uint(...) */
284 
285 /* str2short - safely convert string to int16_t
286  *
287  * @str: source string to convert from
288  * @shrt_ptr: pointer where to store result
289  *
290  * returns zero on success
291  * returns (-1) if one of args is NULL, (-2) invalid input, (-3) for *flow
292  */
293 int str2short(const char * str, int16_t * shrt_ptr)
294 {
295 	int rc = (-3);
296 	int64_t arg_long = 0;
297 	if (!str || !shrt_ptr)
298 		return (-1);
299 
300 	if ( (rc = str2long(str, &arg_long)) != 0 ) {
301 		*shrt_ptr = 0;
302 		return rc;
303 	}
304 
305 	if (arg_long < INT16_MIN || arg_long > INT16_MAX)
306 		return (-3);
307 
308 	*shrt_ptr = (int16_t)arg_long;
309 	return 0;
310 } /* str2short(...) */
311 
312 /* str2ushort - safely convert string to uint16_t
313  *
314  * @str: source string to convert from
315  * @ushrt_ptr: pointer where to store result
316  *
317  * returns zero on success
318  * returns (-1) if one of args is NULL, (-2) invalid input, (-3) for *flow
319  */
320 int str2ushort(const char * str, uint16_t * ushrt_ptr)
321 {
322 	int rc = (-3);
323 	uint64_t arg_ulong = 0;
324 	if (!str || !ushrt_ptr)
325 		return (-1);
326 
327 	if ( (rc = str2ulong(str, &arg_ulong)) != 0 ) {
328 		*ushrt_ptr = 0;
329 		return rc;
330 	}
331 
332 	if (arg_ulong > UINT16_MAX)
333 		return (-3);
334 
335 	*ushrt_ptr = (uint16_t)arg_ulong;
336 	return 0;
337 } /* str2ushort(...) */
338 
339 /* str2char - safely convert string to int8
340  *
341  * @str: source string to convert from
342  * @chr_ptr: pointer where to store result
343  *
344  * returns zero on success
345  * returns (-1) if one of args is NULL, (-2) or (-3) if conversion fails
346  */
347 int str2char(const char *str, int8_t * chr_ptr)
348 {
349 	int rc = (-3);
350 	int64_t arg_long = 0;
351 	if (!str || !chr_ptr) {
352 		return (-1);
353 	}
354 	if ((rc = str2long(str, &arg_long)) != 0) {
355 		*chr_ptr = 0;
356 		return rc;
357 	}
358 	if (arg_long < INT8_MIN || arg_long > INT8_MAX) {
359 		return (-3);
360 	}
361 	*chr_ptr = (uint8_t)arg_long;
362 	return 0;
363 } /* str2char(...) */
364 
365 /* str2uchar - safely convert string to uint8
366  *
367  * @str: source string to convert from
368  * @uchr_ptr: pointer where to store result
369  *
370  * returns zero on success
371  * returns (-1) if one of args is NULL, (-2) or (-3) if conversion fails
372  */
373 int str2uchar(const char * str, uint8_t * uchr_ptr)
374 {
375 	int rc = (-3);
376 	uint64_t arg_ulong = 0;
377 	if (!str || !uchr_ptr)
378 		return (-1);
379 
380 	if ( (rc = str2ulong(str, &arg_ulong)) != 0 ) {
381 		*uchr_ptr = 0;
382 		return rc;
383 	}
384 
385 	if (arg_ulong > UINT8_MAX)
386 		return (-3);
387 
388 	*uchr_ptr = (uint8_t)arg_ulong;
389 	return 0;
390 } /* str2uchar(...) */
391 
392 uint16_t str2val(const char *str, const struct valstr *vs)
393 {
394 	int i;
395 
396 	for (i = 0; vs[i].str != NULL; i++) {
397 		if (strncasecmp(vs[i].str, str, __maxlen(str, vs[i].str)) == 0)
398 			return vs[i].val;
399 	}
400 
401 	return vs[i].val;
402 }
403 
404 /* print_valstr  -  print value string list to log or stdout
405  *
406  * @vs:		value string list to print
407  * @title:	name of this value string list
408  * @loglevel:	what log level to print, -1 for stdout
409  */
410 void
411 print_valstr(const struct valstr * vs, const char * title, int loglevel)
412 {
413 	int i;
414 
415 	if (vs == NULL)
416 		return;
417 
418 	if (title != NULL) {
419 		if (loglevel < 0)
420 			printf("\n%s:\n\n", title);
421 		else
422 			lprintf(loglevel, "\n%s:\n", title);
423 	}
424 
425 	if (loglevel < 0) {
426 		printf("  VALUE\tHEX\tSTRING\n");
427 		printf("==============================================\n");
428 	} else {
429 		lprintf(loglevel, "  VAL\tHEX\tSTRING");
430 		lprintf(loglevel, "==============================================");
431 	}
432 
433 	for (i = 0; vs[i].str != NULL; i++) {
434 		if (loglevel < 0) {
435 			if (vs[i].val < 256)
436 				printf("  %d\t0x%02x\t%s\n", vs[i].val, vs[i].val, vs[i].str);
437 			else
438 				printf("  %d\t0x%04x\t%s\n", vs[i].val, vs[i].val, vs[i].str);
439 		} else {
440 			if (vs[i].val < 256)
441 				lprintf(loglevel, "  %d\t0x%02x\t%s", vs[i].val, vs[i].val, vs[i].str);
442 			else
443 				lprintf(loglevel, "  %d\t0x%04x\t%s", vs[i].val, vs[i].val, vs[i].str);
444 		}
445 	}
446 
447 	if (loglevel < 0)
448 		printf("\n");
449 	else
450 		lprintf(loglevel, "");
451 }
452 
453 /* print_valstr_2col  -  print value string list in two columns to log or stdout
454  *
455  * @vs:		value string list to print
456  * @title:	name of this value string list
457  * @loglevel:	what log level to print, -1 for stdout
458  */
459 void
460 print_valstr_2col(const struct valstr * vs, const char * title, int loglevel)
461 {
462 	int i;
463 
464 	if (vs == NULL)
465 		return;
466 
467 	if (title != NULL) {
468 		if (loglevel < 0)
469 			printf("\n%s:\n\n", title);
470 		else
471 			lprintf(loglevel, "\n%s:\n", title);
472 	}
473 
474 	for (i = 0; vs[i].str != NULL; i++) {
475 		if (vs[i+1].str == NULL) {
476 			/* last one */
477 			if (loglevel < 0) {
478 				printf("  %4d  %-32s\n", vs[i].val, vs[i].str);
479 			} else {
480 				lprintf(loglevel, "  %4d  %-32s\n", vs[i].val, vs[i].str);
481 			}
482 		}
483 		else {
484 			if (loglevel < 0) {
485 				printf("  %4d  %-32s    %4d  %-32s\n",
486 				       vs[i].val, vs[i].str, vs[i+1].val, vs[i+1].str);
487 			} else {
488 				lprintf(loglevel, "  %4d  %-32s    %4d  %-32s\n",
489 					vs[i].val, vs[i].str, vs[i+1].val, vs[i+1].str);
490 			}
491 			i++;
492 		}
493 	}
494 
495 	if (loglevel < 0)
496 		printf("\n");
497 	else
498 		lprintf(loglevel, "");
499 }
500 
501 /* ipmi_csum  -  calculate an ipmi checksum
502  *
503  * @d:		buffer to check
504  * @s:		position in buffer to start checksum from
505  */
506 uint8_t
507 ipmi_csum(uint8_t * d, int s)
508 {
509 	uint8_t c = 0;
510 	for (; s > 0; s--, d++)
511 		c += *d;
512 	return -c;
513 }
514 
515 /* ipmi_open_file  -  safely open a file for reading or writing
516  *
517  * @file:	filename
518  * @rw:		read-write flag, 1=write
519  *
520  * returns pointer to file handler on success
521  * returns NULL on error
522  */
523 FILE *
524 ipmi_open_file(const char * file, int rw)
525 {
526 	struct stat st1, st2;
527 	FILE * fp;
528 
529 	/* verify existance */
530 	if (lstat(file, &st1) < 0) {
531 		if (rw) {
532 			/* does not exist, ok to create */
533 			fp = fopen(file, "w");
534 			if (fp == NULL) {
535 				lperror(LOG_ERR, "Unable to open file %s "
536 					"for write", file);
537 				return NULL;
538 			}
539 			/* created ok, now return the descriptor */
540 			return fp;
541 		} else {
542 			lprintf(LOG_ERR, "File %s does not exist", file);
543 			return NULL;
544 		}
545 	}
546 
547 #ifndef ENABLE_FILE_SECURITY
548 	if (!rw) {
549 		/* on read skip the extra checks */
550 		fp = fopen(file, "r");
551 		if (fp == NULL) {
552 			lperror(LOG_ERR, "Unable to open file %s", file);
553 			return NULL;
554 		}
555 		return fp;
556 	}
557 #endif
558 
559 	/* it exists - only regular files, not links */
560 	if (S_ISREG(st1.st_mode) == 0) {
561 		lprintf(LOG_ERR, "File %s has invalid mode: %d",
562 			file, st1.st_mode);
563 		return NULL;
564 	}
565 
566 	/* allow only files with 1 link (itself) */
567 	if (st1.st_nlink != 1) {
568 		lprintf(LOG_ERR, "File %s has invalid link count: %d != 1",
569 		       file, (int)st1.st_nlink);
570 		return NULL;
571 	}
572 
573 	fp = fopen(file, rw ? "w+" : "r");
574 	if (fp == NULL) {
575 		lperror(LOG_ERR, "Unable to open file %s", file);
576 		return NULL;
577 	}
578 
579 	/* stat again */
580 	if (fstat(fileno(fp), &st2) < 0) {
581 		lperror(LOG_ERR, "Unable to stat file %s", file);
582 		fclose(fp);
583 		return NULL;
584 	}
585 
586 	/* verify inode */
587 	if (st1.st_ino != st2.st_ino) {
588 		lprintf(LOG_ERR, "File %s has invalid inode: %d != %d",
589 			file, st1.st_ino, st2.st_ino);
590 		fclose(fp);
591 		return NULL;
592 	}
593 
594 	/* verify owner */
595 	if (st1.st_uid != st2.st_uid) {
596 		lprintf(LOG_ERR, "File %s has invalid user id: %d != %d",
597 			file, st1.st_uid, st2.st_uid);
598 		fclose(fp);
599 		return NULL;
600 	}
601 
602 	/* verify inode */
603 	if (st2.st_nlink != 1) {
604 		lprintf(LOG_ERR, "File %s has invalid link count: %d != 1",
605 			file, st2.st_nlink);
606 		fclose(fp);
607 		return NULL;
608 	}
609 
610 	return fp;
611 }
612 
613 void
614 ipmi_start_daemon(struct ipmi_intf *intf)
615 {
616 	pid_t pid;
617 	int fd;
618 #ifdef SIGHUP
619 	sigset_t sighup;
620 #endif
621 
622 #ifdef SIGHUP
623 	sigemptyset(&sighup);
624 	sigaddset(&sighup, SIGHUP);
625 	if (sigprocmask(SIG_UNBLOCK, &sighup, NULL) < 0)
626 		fprintf(stderr, "ERROR: could not unblock SIGHUP signal\n");
627 	signal(SIGHUP, SIG_IGN);
628 #endif
629 #ifdef SIGTTOU
630 	signal(SIGTTOU, SIG_IGN);
631 #endif
632 #ifdef SIGTTIN
633 	signal(SIGTTIN, SIG_IGN);
634 #endif
635 #ifdef SIGQUIT
636 	signal(SIGQUIT, SIG_IGN);
637 #endif
638 #ifdef SIGTSTP
639 	signal(SIGTSTP, SIG_IGN);
640 #endif
641 
642 	pid = (pid_t) fork();
643 	if (pid < 0 || pid > 0)
644 		exit(0);
645 
646 #if defined(SIGTSTP) && defined(TIOCNOTTY)
647 	if (setpgid(0, getpid()) == -1)
648 		exit(1);
649 	if ((fd = open(_PATH_TTY, O_RDWR)) >= 0) {
650 		ioctl(fd, TIOCNOTTY, NULL);
651 		close(fd);
652 	}
653 #else
654 	if (setpgid(0, 0) == -1)
655 		exit(1);
656 	pid = (pid_t) fork();
657 	if (pid < 0 || pid > 0)
658 		exit(0);
659 #endif
660 
661 	chdir("/");
662 	umask(0);
663 
664 	for (fd=0; fd<64; fd++) {
665 		if (fd != intf->fd)
666 			close(fd);
667 	}
668 
669 	fd = open("/dev/null", O_RDWR);
670 	assert(0 == fd);
671 	dup(fd);
672 	dup(fd);
673 }
674 
675 /* eval_ccode - evaluate return value of _ipmi_* functions and print error error
676  * message, if conditions are met.
677  *
678  * @ccode - return value of _ipmi_* function.
679  *
680  * returns - 0 if ccode is 0, otherwise (-1) and error might get printed-out.
681  */
682 int
683 eval_ccode(const int ccode)
684 {
685 	if (ccode == 0) {
686 		return 0;
687 	} else if (ccode < 0) {
688 		switch (ccode) {
689 			case (-1):
690 				lprintf(LOG_ERR, "IPMI response is NULL.");
691 				break;
692 			case (-2):
693 				lprintf(LOG_ERR, "Unexpected data length received.");
694 				break;
695 			case (-3):
696 				lprintf(LOG_ERR, "Invalid function parameter.");
697 				break;
698 			case (-4):
699 				lprintf(LOG_ERR, "ipmitool: malloc failure.");
700 				break;
701 			default:
702 				break;
703 		}
704 		return (-1);
705 	} else {
706 		lprintf(LOG_ERR, "IPMI command failed: %s",
707 				val2str(ccode, completion_code_vals));
708 		return (-1);
709 	}
710 }
711 
712 /* is_fru_id - wrapper for str-2-int FRU ID conversion. Message is printed
713  * on error.
714  * FRU ID range: <0..255>
715  *
716  * @argv_ptr: source string to convert from; usually argv
717  * @fru_id_ptr: pointer where to store result
718  *
719  * returns zero on success
720  * returns (-1) on error and message is printed on STDERR
721  */
722 int
723 is_fru_id(const char *argv_ptr, uint8_t *fru_id_ptr)
724 {
725 	if (!argv_ptr || !fru_id_ptr) {
726 		lprintf(LOG_ERR, "is_fru_id(): invalid argument(s).");
727 		return (-1);
728 	}
729 
730 	if (str2uchar(argv_ptr, fru_id_ptr) == 0) {
731 		return 0;
732 	}
733 	lprintf(LOG_ERR, "FRU ID '%s' is either invalid or out of range.",
734 			argv_ptr);
735 	return (-1);
736 } /* is_fru_id(...) */
737 
738 /* is_ipmi_channel_num - wrapper for str-2-int Channel conversion. Message is
739  * printed on error.
740  *
741  * 6.3 Channel Numbers, p. 49, IPMIv2 spec. rev1.1
742  * Valid channel numbers are: <0x0..0xB>, <0xE-0xF>
743  * Reserved channel numbers: <0xC-0xD>
744  *
745  * @argv_ptr: source string to convert from; usually argv
746  * @channel_ptr: pointer where to store result
747  *
748  * returns zero on success
749  * returns (-1) on error and message is printed on STDERR
750  */
751 int
752 is_ipmi_channel_num(const char *argv_ptr, uint8_t *channel_ptr)
753 {
754 	if (!argv_ptr || !channel_ptr) {
755 		lprintf(LOG_ERR,
756 				"is_ipmi_channel_num(): invalid argument(s).");
757 		return (-1);
758 	}
759 	if ((str2uchar(argv_ptr, channel_ptr) == 0)
760 			&& (*channel_ptr <= 0xB
761 				|| (*channel_ptr >= 0xE && *channel_ptr <= 0xF))) {
762 		return 0;
763 	}
764 	lprintf(LOG_ERR,
765 			"Given Channel number '%s' is either invalid or out of range.",
766 			argv_ptr);
767 	lprintf(LOG_ERR, "Channel number must be from ranges: <0x0..0xB>, <0xE..0xF>");
768 	return (-1);
769 }
770 
771 /* is_ipmi_user_id() - wrapper for str-2-uint IPMI UID conversion. Message is
772  * printed on error.
773  *
774  * @argv_ptr: source string to convert from; usually argv
775  * @ipmi_uid_ptr: pointer where to store result
776  *
777  * returns zero on success
778  * returns (-1) on error and message is printed on STDERR
779  */
780 int
781 is_ipmi_user_id(const char *argv_ptr, uint8_t *ipmi_uid_ptr)
782 {
783 	if (!argv_ptr || !ipmi_uid_ptr) {
784 		lprintf(LOG_ERR,
785 				"is_ipmi_user_id(): invalid argument(s).");
786 		return (-1);
787 	}
788 	if ((str2uchar(argv_ptr, ipmi_uid_ptr) == 0)
789 			&& *ipmi_uid_ptr >= IPMI_UID_MIN
790 			&& *ipmi_uid_ptr <= IPMI_UID_MAX) {
791 		return 0;
792 	}
793 	lprintf(LOG_ERR,
794 			"Given User ID '%s' is either invalid or out of range.",
795 			argv_ptr);
796 	lprintf(LOG_ERR, "User ID is limited to range <%i..%i>.",
797 			IPMI_UID_MIN, IPMI_UID_MAX);
798 	return (-1);
799 }
800 
801 /* is_ipmi_user_priv_limit - check whether given value is valid User Privilege
802  * Limit, eg. IPMI v2 spec, 22.27 Get User Access Command.
803  *
804  * @priv_limit: User Privilege Limit
805  *
806  * returns 0 if Priv Limit is valid
807  * returns (-1) when Priv Limit is invalid
808  */
809 int
810 is_ipmi_user_priv_limit(const char *argv_ptr, uint8_t *ipmi_priv_limit_ptr)
811 {
812 	if (!argv_ptr || !ipmi_priv_limit_ptr) {
813 		lprintf(LOG_ERR,
814 				"is_ipmi_user_priv_limit(): invalid argument(s).");
815 		return (-1);
816 	}
817 	if ((str2uchar(argv_ptr, ipmi_priv_limit_ptr) != 0)
818 			|| ((*ipmi_priv_limit_ptr < 0x01
819 				|| *ipmi_priv_limit_ptr > 0x05)
820 				&& *ipmi_priv_limit_ptr != 0x0F)) {
821 		lprintf(LOG_ERR,
822 				"Given Privilege Limit '%s' is invalid.",
823 				argv_ptr);
824 		lprintf(LOG_ERR,
825 				"Privilege Limit is limited to <0x1..0x5> and <0xF>.");
826 		return (-1);
827 	}
828 	return 0;
829 }
830 
831 uint16_t
832 ipmi_get_oem_id(struct ipmi_intf *intf)
833 {
834 	/* Execute a Get Board ID command to determine the board */
835 	struct ipmi_rs *rsp;
836 	struct ipmi_rq req;
837 	uint16_t oem_id;
838 
839 	memset(&req, 0, sizeof(req));
840 	req.msg.netfn = IPMI_NETFN_TSOL;
841 	req.msg.cmd   = 0x21;
842 	req.msg.data_len = 0;
843 
844 	rsp = intf->sendrecv(intf, &req);
845 	if (rsp == NULL) {
846 		lprintf(LOG_ERR, "Get Board ID command failed");
847 		return 0;
848 	}
849 	if (rsp->ccode > 0) {
850 		lprintf(LOG_ERR, "Get Board ID command failed: %#x %s",
851 			rsp->ccode, val2str(rsp->ccode, completion_code_vals));
852 		return 0;
853 	}
854 	oem_id = rsp->data[0] | (rsp->data[1] << 8);
855 	lprintf(LOG_DEBUG,"Board ID: %x", oem_id);
856 
857 	return oem_id;
858 }
859