mirror of
https://github.com/ipmitool/ipmitool.git
synced 2025-05-10 18:47:22 +00:00
This patch adds basic long message support for PICMG-based systems according to the HPM.2 specification. It also introduces APIs for setting inbound and outbound messages sizes per selected interface. This APIs are used in LAN and LAN+ interfaces to set autonomously detected inbound and outbound message sizes. The newly introduced APIs also replace the existing message size detection code in several ipmitool commands in order to leverage the advantages of long message support (HPM.1 upgrade, SDR acquring, FRU inventory read and write). The Kontron-specific long message support is moved under a OEM option. Commit for Dmitry Bazhenov
1064 lines
29 KiB
C
1064 lines
29 KiB
C
/*
|
|
* Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* Redistribution of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
*
|
|
* Redistribution in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* Neither the name of Sun Microsystems, Inc. or the names of
|
|
* contributors may be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
*
|
|
* This software is provided "AS IS," without a warranty of any kind.
|
|
* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
|
|
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
|
|
* PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
|
|
* SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
|
|
* FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
|
|
* OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
|
|
* SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
|
|
* OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
|
|
* PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
|
|
* LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
|
|
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <inttypes.h>
|
|
#include <signal.h>
|
|
#include <string.h>
|
|
#include <strings.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <errno.h>
|
|
#include <ctype.h>
|
|
|
|
#include <ipmitool/helper.h>
|
|
#include <ipmitool/log.h>
|
|
#include <ipmitool/ipmi.h>
|
|
#include <ipmitool/ipmi_intf.h>
|
|
#include <ipmitool/ipmi_session.h>
|
|
#include <ipmitool/ipmi_sdr.h>
|
|
#include <ipmitool/ipmi_gendev.h>
|
|
#include <ipmitool/ipmi_sel.h>
|
|
#include <ipmitool/ipmi_fru.h>
|
|
#include <ipmitool/ipmi_sol.h>
|
|
#include <ipmitool/ipmi_isol.h>
|
|
#include <ipmitool/ipmi_lanp.h>
|
|
#include <ipmitool/ipmi_chassis.h>
|
|
#include <ipmitool/ipmi_mc.h>
|
|
#include <ipmitool/ipmi_firewall.h>
|
|
#include <ipmitool/ipmi_sensor.h>
|
|
#include <ipmitool/ipmi_channel.h>
|
|
#include <ipmitool/ipmi_session.h>
|
|
#include <ipmitool/ipmi_event.h>
|
|
#include <ipmitool/ipmi_user.h>
|
|
#include <ipmitool/ipmi_raw.h>
|
|
#include <ipmitool/ipmi_pef.h>
|
|
#include <ipmitool/ipmi_oem.h>
|
|
#include <ipmitool/ipmi_ekanalyzer.h>
|
|
#include <ipmitool/ipmi_picmg.h>
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include <config.h>
|
|
#endif
|
|
|
|
#ifdef ENABLE_ALL_OPTIONS
|
|
# define OPTION_STRING "I:hVvcgsEKYao:H:d:P:f:U:p:C:L:A:t:T:m:z:S:l:b:B:e:k:y:O:R:N:D:"
|
|
#else
|
|
# define OPTION_STRING "I:hVvcH:f:U:p:d:S:D:"
|
|
#endif
|
|
|
|
extern int verbose;
|
|
extern int csv_output;
|
|
extern const struct valstr ipmi_privlvl_vals[];
|
|
extern const struct valstr ipmi_authtype_session_vals[];
|
|
|
|
static struct ipmi_intf * ipmi_main_intf = NULL;
|
|
|
|
/* ipmi_password_file_read - Open file and read password from it
|
|
*
|
|
* @filename: file name to read from
|
|
*
|
|
* returns pointer to allocated buffer containing password
|
|
* (caller is expected to free when finished)
|
|
* returns NULL on error
|
|
*/
|
|
static char *
|
|
ipmi_password_file_read(char * filename)
|
|
{
|
|
FILE * fp;
|
|
char * pass = NULL;
|
|
int l;
|
|
|
|
pass = malloc(21);
|
|
if (pass == NULL) {
|
|
lprintf(LOG_ERR, "ipmitool: malloc failure");
|
|
return NULL;
|
|
}
|
|
|
|
memset(pass, 0, 21);
|
|
fp = ipmi_open_file_read((const char *)filename);
|
|
if (fp == NULL) {
|
|
lprintf(LOG_ERR, "Unable to open password file %s",
|
|
filename);
|
|
free(pass);
|
|
return NULL;
|
|
}
|
|
|
|
/* read in id */
|
|
if (fgets(pass, 21, fp) == NULL) {
|
|
lprintf(LOG_ERR, "Unable to read password from file %s",
|
|
filename);
|
|
free(pass);
|
|
fclose(fp);
|
|
return NULL;
|
|
}
|
|
|
|
/* remove trailing whitespace */
|
|
l = strcspn(pass, " \r\n\t");
|
|
if (l > 0) {
|
|
pass[l] = '\0';
|
|
}
|
|
|
|
fclose(fp);
|
|
return pass;
|
|
}
|
|
|
|
|
|
/*
|
|
* Print all the commands in the above table to stderr
|
|
* used for help text on command line and shell
|
|
*/
|
|
void
|
|
ipmi_cmd_print(struct ipmi_cmd * cmdlist)
|
|
{
|
|
struct ipmi_cmd * cmd;
|
|
int hdr = 0;
|
|
|
|
if (cmdlist == NULL)
|
|
return;
|
|
for (cmd=cmdlist; cmd->func != NULL; cmd++) {
|
|
if (cmd->desc == NULL)
|
|
continue;
|
|
if (hdr == 0) {
|
|
lprintf(LOG_NOTICE, "Commands:");
|
|
hdr = 1;
|
|
}
|
|
lprintf(LOG_NOTICE, "\t%-12s %s", cmd->name, cmd->desc);
|
|
}
|
|
lprintf(LOG_NOTICE, "");
|
|
}
|
|
|
|
/* ipmi_cmd_run - run a command from list based on parameters
|
|
* called from main()
|
|
*
|
|
* 1. iterate through ipmi_cmd_list matching on name
|
|
* 2. call func() for that command
|
|
*
|
|
* @intf: ipmi interface
|
|
* @name: command name
|
|
* @argc: command argument count
|
|
* @argv: command argument list
|
|
*
|
|
* returns value from func() of that commnad if found
|
|
* returns -1 if command is not found
|
|
*/
|
|
int
|
|
ipmi_cmd_run(struct ipmi_intf * intf, char * name, int argc, char ** argv)
|
|
{
|
|
struct ipmi_cmd * cmd = intf->cmdlist;
|
|
|
|
/* hook to run a default command if nothing specified */
|
|
if (name == NULL) {
|
|
if (cmd->func == NULL || cmd->name == NULL)
|
|
return -1;
|
|
else if (strncmp(cmd->name, "default", 7) == 0)
|
|
return cmd->func(intf, 0, NULL);
|
|
else {
|
|
lprintf(LOG_ERR, "No command provided!");
|
|
ipmi_cmd_print(intf->cmdlist);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
for (cmd=intf->cmdlist; cmd->func != NULL; cmd++) {
|
|
if (strncmp(name, cmd->name, __maxlen(cmd->name, name)) == 0)
|
|
break;
|
|
}
|
|
if (cmd->func == NULL) {
|
|
cmd = intf->cmdlist;
|
|
if (strncmp(cmd->name, "default", 7) == 0)
|
|
return cmd->func(intf, argc+1, argv-1);
|
|
|
|
lprintf(LOG_ERR, "Invalid command: %s", name);
|
|
ipmi_cmd_print(intf->cmdlist);
|
|
return -1;
|
|
}
|
|
return cmd->func(intf, argc, argv);
|
|
}
|
|
|
|
static void
|
|
ipmi_option_usage(const char * progname, struct ipmi_cmd * cmdlist, struct ipmi_intf_support * intflist)
|
|
{
|
|
lprintf(LOG_NOTICE, "%s version %s\n", progname, VERSION);
|
|
lprintf(LOG_NOTICE, "usage: %s [options...] <command>\n", progname);
|
|
lprintf(LOG_NOTICE, " -h This help");
|
|
lprintf(LOG_NOTICE, " -V Show version information");
|
|
lprintf(LOG_NOTICE, " -v Verbose (can use multiple times)");
|
|
lprintf(LOG_NOTICE, " -c Display output in comma separated format");
|
|
lprintf(LOG_NOTICE, " -d N Specify a /dev/ipmiN device to use (default=0)");
|
|
lprintf(LOG_NOTICE, " -I intf Interface to use");
|
|
lprintf(LOG_NOTICE, " -H hostname Remote host name for LAN interface");
|
|
lprintf(LOG_NOTICE, " -p port Remote RMCP port [default=623]");
|
|
lprintf(LOG_NOTICE, " -U username Remote session username");
|
|
lprintf(LOG_NOTICE, " -f file Read remote session password from file");
|
|
lprintf(LOG_NOTICE, " -z size Change Size of Communication Channel (OEM)");
|
|
lprintf(LOG_NOTICE, " -S sdr Use local file for remote SDR cache");
|
|
lprintf(LOG_NOTICE, " -D tty:b[:s] Specify the serial device, baud rate to use");
|
|
lprintf(LOG_NOTICE, " and, optionally, specify that interface is the system one");
|
|
#ifdef ENABLE_ALL_OPTIONS
|
|
lprintf(LOG_NOTICE, " -a Prompt for remote password");
|
|
lprintf(LOG_NOTICE, " -Y Prompt for the Kg key for IPMIv2 authentication");
|
|
lprintf(LOG_NOTICE, " -e char Set SOL escape character");
|
|
lprintf(LOG_NOTICE, " -C ciphersuite Cipher suite to be used by lanplus interface");
|
|
lprintf(LOG_NOTICE, " -k key Use Kg key for IPMIv2 authentication");
|
|
lprintf(LOG_NOTICE, " -y hex_key Use hexadecimal-encoded Kg key for IPMIv2 authentication");
|
|
lprintf(LOG_NOTICE, " -L level Remote session privilege level [default=ADMINISTRATOR]");
|
|
lprintf(LOG_NOTICE, " Append a '+' to use name/privilege lookup in RAKP1");
|
|
lprintf(LOG_NOTICE, " -A authtype Force use of auth type NONE, PASSWORD, MD2, MD5 or OEM");
|
|
lprintf(LOG_NOTICE, " -P password Remote session password");
|
|
lprintf(LOG_NOTICE, " -E Read password from IPMI_PASSWORD environment variable");
|
|
lprintf(LOG_NOTICE, " -K Read kgkey from IPMI_KGKEY environment variable");
|
|
lprintf(LOG_NOTICE, " -m address Set local IPMB address");
|
|
lprintf(LOG_NOTICE, " -b channel Set destination channel for bridged request");
|
|
lprintf(LOG_NOTICE, " -t address Bridge request to remote target address");
|
|
lprintf(LOG_NOTICE, " -B channel Set transit channel for bridged request (dual bridge)");
|
|
lprintf(LOG_NOTICE, " -T address Set transit address for bridge request (dual bridge)");
|
|
lprintf(LOG_NOTICE, " -l lun Set destination lun for raw commands");
|
|
lprintf(LOG_NOTICE, " -o oemtype Setup for OEM (use 'list' to see available OEM types)");
|
|
lprintf(LOG_NOTICE, " -O seloem Use file for OEM SEL event descriptions");
|
|
lprintf(LOG_NOTICE, " -N seconds Specify timeout for lan [default=2] / lanplus [default=1] interface");
|
|
lprintf(LOG_NOTICE, " -R retry Set the number of retries for lan/lanplus interface [default=4]");
|
|
#endif
|
|
lprintf(LOG_NOTICE, "");
|
|
|
|
ipmi_intf_print(intflist);
|
|
|
|
if (cmdlist != NULL)
|
|
ipmi_cmd_print(cmdlist);
|
|
}
|
|
/* ipmi_catch_sigint - Handle the interrupt signal (Ctrl-C), close the
|
|
* interface, and exit ipmitool with error (-1)
|
|
*
|
|
* This insures that the IOL session gets freed
|
|
* for other callers.
|
|
*
|
|
* returns -1
|
|
*/
|
|
void ipmi_catch_sigint()
|
|
{
|
|
if (ipmi_main_intf != NULL) {
|
|
printf("\nSIGN INT: Close Interface %s\n",ipmi_main_intf->desc);
|
|
ipmi_main_intf->close(ipmi_main_intf);
|
|
}
|
|
exit(-1);
|
|
}
|
|
|
|
/* ipmi_parse_hex - convert hexadecimal numbers to ascii string
|
|
* Input string must be composed of two-characer hexadecimal numbers.
|
|
* There is no separator between the numbers. Each number results in one character
|
|
* of the converted string.
|
|
*
|
|
* Example: ipmi_parse_hex("50415353574F5244") returns 'PASSWORD'
|
|
*
|
|
* @param str: input string. It must contain only even number of '0'-'9','a'-'f' and 'A-F' characters.
|
|
* @returns converted ascii string
|
|
* @returns NULL on error
|
|
*/
|
|
static unsigned char *
|
|
ipmi_parse_hex(const char *str)
|
|
{
|
|
const char * p;
|
|
unsigned char * out, *q;
|
|
unsigned char b = 0;
|
|
int shift = 4;
|
|
|
|
if (strlen(str) == 0)
|
|
return NULL;
|
|
|
|
if (strlen(str) % 2 != 0) {
|
|
lprintf(LOG_ERR, "Number of hex_kg characters is not even");
|
|
return NULL;
|
|
}
|
|
|
|
if (strlen(str) > (IPMI_KG_BUFFER_SIZE-1)*2) {
|
|
lprintf(LOG_ERR, "Kg key is too long");
|
|
return NULL;
|
|
}
|
|
|
|
out = calloc(IPMI_KG_BUFFER_SIZE, sizeof(unsigned char));
|
|
if (out == NULL) {
|
|
lprintf(LOG_ERR, "malloc failure");
|
|
return NULL;
|
|
}
|
|
|
|
for (p = str, q = out; *p; p++) {
|
|
if (!isxdigit(*p)) {
|
|
lprintf(LOG_ERR, "Kg_hex is not hexadecimal number");
|
|
free(out);
|
|
out = NULL;
|
|
return NULL;
|
|
}
|
|
|
|
if (*p < 'A') /* it must be 0-9 */
|
|
b = *p - '0';
|
|
else /* it's A-F or a-f */
|
|
b = (*p | 0x20) - 'a' + 10; /* convert to lowercase and to 10-15 */
|
|
|
|
*q = *q + b << shift;
|
|
if (shift)
|
|
shift = 0;
|
|
else {
|
|
shift = 4;
|
|
q++;
|
|
}
|
|
}
|
|
|
|
return out;
|
|
}
|
|
|
|
/* ipmi_parse_options - helper function to handle parsing command line options
|
|
*
|
|
* @argc: count of options
|
|
* @argv: list of options
|
|
* @cmdlist: list of supported commands
|
|
* @intflist: list of supported interfaces
|
|
*
|
|
* returns 0 on success
|
|
* returns -1 on error
|
|
*/
|
|
int
|
|
ipmi_main(int argc, char ** argv,
|
|
struct ipmi_cmd * cmdlist,
|
|
struct ipmi_intf_support * intflist)
|
|
{
|
|
struct ipmi_intf_support * sup;
|
|
int privlvl = 0;
|
|
uint8_t target_addr = 0;
|
|
uint8_t target_channel = 0;
|
|
|
|
uint8_t transit_addr = 0;
|
|
uint8_t transit_channel = 0;
|
|
uint8_t target_lun = 0;
|
|
uint8_t arg_addr = 0;
|
|
uint8_t addr = 0;
|
|
uint16_t my_long_packet_size=0;
|
|
uint8_t my_long_packet_set=0;
|
|
uint8_t lookupbit = 0x10; /* use name-only lookup by default */
|
|
int retry = 0;
|
|
uint32_t timeout = 0;
|
|
int authtype = -1;
|
|
char * tmp_pass = NULL;
|
|
char * tmp_env = NULL;
|
|
char * hostname = NULL;
|
|
char * username = NULL;
|
|
char * password = NULL;
|
|
char * intfname = NULL;
|
|
char * progname = NULL;
|
|
char * oemtype = NULL;
|
|
char * sdrcache = NULL;
|
|
unsigned char * kgkey = NULL;
|
|
char * seloem = NULL;
|
|
int port = 0;
|
|
int devnum = 0;
|
|
int cipher_suite_id = 3; /* See table 22-19 of the IPMIv2 spec */
|
|
int argflag, i, found;
|
|
int rc = -1;
|
|
char sol_escape_char = SOL_ESCAPE_CHARACTER_DEFAULT;
|
|
char * devfile = NULL;
|
|
|
|
/* save program name */
|
|
progname = strrchr(argv[0], '/');
|
|
progname = ((progname == NULL) ? argv[0] : progname+1);
|
|
signal(SIGINT, ipmi_catch_sigint);
|
|
|
|
while ((argflag = getopt(argc, (char **)argv, OPTION_STRING)) != -1)
|
|
{
|
|
switch (argflag) {
|
|
case 'I':
|
|
if (intfname) {
|
|
free(intfname);
|
|
intfname = NULL;
|
|
}
|
|
intfname = strdup(optarg);
|
|
if (intfname == NULL) {
|
|
lprintf(LOG_ERR, "%s: malloc failure", progname);
|
|
goto out_free;
|
|
}
|
|
if (intflist != NULL) {
|
|
found = 0;
|
|
for (sup=intflist; sup->name != NULL; sup++) {
|
|
if (strncmp(sup->name, intfname, strlen(intfname)) == 0 &&
|
|
strncmp(sup->name, intfname, strlen(sup->name)) == 0 &&
|
|
sup->supported == 1)
|
|
found = 1;
|
|
}
|
|
if (!found) {
|
|
lprintf(LOG_ERR, "Interface %s not supported", intfname);
|
|
goto out_free;
|
|
}
|
|
}
|
|
break;
|
|
case 'h':
|
|
ipmi_option_usage(progname, cmdlist, intflist);
|
|
rc = 0;
|
|
goto out_free;
|
|
break;
|
|
case 'V':
|
|
printf("%s version %s\n", progname, VERSION);
|
|
rc = 0;
|
|
goto out_free;
|
|
break;
|
|
case 'd':
|
|
if (str2int(optarg, &devnum) != 0) {
|
|
lprintf(LOG_ERR, "Invalid parameter given or out of range for '-d'.");
|
|
rc = -1;
|
|
goto out_free;
|
|
}
|
|
/* Check if device number is -gt 0; I couldn't find limit for
|
|
* kernels > 2.6, thus right side is unlimited.
|
|
*/
|
|
if (devnum < 0) {
|
|
lprintf(LOG_ERR, "Device number %i is out of range.", devnum);
|
|
rc = -1;
|
|
goto out_free;
|
|
}
|
|
break;
|
|
case 'p':
|
|
if (str2int(optarg, &port) != 0) {
|
|
lprintf(LOG_ERR, "Invalid parameter given or out of range for '-p'.");
|
|
rc = -1;
|
|
goto out_free;
|
|
}
|
|
/* Check if port is -gt 0 && port is -lt 65535 */
|
|
if (port < 0 || port > 65535) {
|
|
lprintf(LOG_ERR, "Port number %i is out of range.", port);
|
|
rc = -1;
|
|
goto out_free;
|
|
}
|
|
break;
|
|
case 'C':
|
|
if (str2int(optarg, &cipher_suite_id) != 0) {
|
|
lprintf(LOG_ERR, "Invalid parameter given or out of range for '-C'.");
|
|
rc = -1;
|
|
goto out_free;
|
|
}
|
|
/* add check Cipher is -gt 0 */
|
|
if (cipher_suite_id < 0) {
|
|
lprintf(LOG_ERR, "Cipher suite ID %i is invalid.", cipher_suite_id);
|
|
rc = -1;
|
|
goto out_free;
|
|
}
|
|
break;
|
|
case 'v':
|
|
verbose++;
|
|
break;
|
|
case 'c':
|
|
csv_output = 1;
|
|
break;
|
|
case 'H':
|
|
if (hostname) {
|
|
free(hostname);
|
|
hostname = NULL;
|
|
}
|
|
hostname = strdup(optarg);
|
|
if (hostname == NULL) {
|
|
lprintf(LOG_ERR, "%s: malloc failure", progname);
|
|
goto out_free;
|
|
}
|
|
break;
|
|
case 'f':
|
|
if (password) {
|
|
free(password);
|
|
password = NULL;
|
|
}
|
|
password = ipmi_password_file_read(optarg);
|
|
if (password == NULL)
|
|
lprintf(LOG_ERR, "Unable to read password "
|
|
"from file %s", optarg);
|
|
break;
|
|
case 'a':
|
|
#ifdef HAVE_GETPASSPHRASE
|
|
tmp_pass = getpassphrase("Password: ");
|
|
#else
|
|
tmp_pass = getpass("Password: ");
|
|
#endif
|
|
if (tmp_pass != NULL) {
|
|
if (password) {
|
|
free(password);
|
|
password = NULL;
|
|
}
|
|
password = strdup(tmp_pass);
|
|
tmp_pass = NULL;
|
|
if (password == NULL) {
|
|
lprintf(LOG_ERR, "%s: malloc failure", progname);
|
|
goto out_free;
|
|
}
|
|
}
|
|
break;
|
|
case 'k':
|
|
if (kgkey) {
|
|
free(kgkey);
|
|
kgkey = NULL;
|
|
}
|
|
kgkey = strdup(optarg);
|
|
if (kgkey == NULL) {
|
|
lprintf(LOG_ERR, "%s: malloc failure", progname);
|
|
goto out_free;
|
|
}
|
|
break;
|
|
case 'K':
|
|
if ((tmp_env = getenv("IPMI_KGKEY"))) {
|
|
if (kgkey) {
|
|
free(kgkey);
|
|
kgkey = NULL;
|
|
}
|
|
kgkey = strdup(tmp_env);
|
|
if (kgkey == NULL) {
|
|
lprintf(LOG_ERR, "%s: malloc failure", progname);
|
|
goto out_free;
|
|
}
|
|
} else {
|
|
lprintf(LOG_WARN, "Unable to read kgkey from environment");
|
|
}
|
|
break;
|
|
case 'y':
|
|
if (kgkey) {
|
|
free(kgkey);
|
|
kgkey = NULL;
|
|
}
|
|
kgkey = ipmi_parse_hex(optarg);
|
|
if (kgkey == NULL) {
|
|
goto out_free;
|
|
}
|
|
break;
|
|
case 'Y':
|
|
#ifdef HAVE_GETPASSPHRASE
|
|
tmp_pass = getpassphrase("Key: ");
|
|
#else
|
|
tmp_pass = getpass("Key: ");
|
|
#endif
|
|
if (tmp_pass != NULL) {
|
|
if (kgkey) {
|
|
free(kgkey);
|
|
kgkey = NULL;
|
|
}
|
|
kgkey = strdup(tmp_pass);
|
|
tmp_pass = NULL;
|
|
if (kgkey == NULL) {
|
|
lprintf(LOG_ERR, "%s: malloc failure", progname);
|
|
goto out_free;
|
|
}
|
|
}
|
|
break;
|
|
case 'U':
|
|
if (username) {
|
|
free(username);
|
|
username = NULL;
|
|
}
|
|
if (strlen(optarg) > 16) {
|
|
lprintf(LOG_ERR, "Username is too long (> 16 bytes)");
|
|
goto out_free;
|
|
}
|
|
username = strdup(optarg);
|
|
if (username == NULL) {
|
|
lprintf(LOG_ERR, "%s: malloc failure", progname);
|
|
goto out_free;
|
|
}
|
|
break;
|
|
case 'S':
|
|
if (sdrcache) {
|
|
free(sdrcache);
|
|
sdrcache = NULL;
|
|
}
|
|
sdrcache = strdup(optarg);
|
|
if (sdrcache == NULL) {
|
|
lprintf(LOG_ERR, "%s: malloc failure", progname);
|
|
goto out_free;
|
|
}
|
|
break;
|
|
case 'D':
|
|
/* check for subsequent instance of -D */
|
|
if (devfile) {
|
|
/* free memory for previous string */
|
|
free(devfile);
|
|
}
|
|
devfile = strdup(optarg);
|
|
if (devfile == NULL) {
|
|
lprintf(LOG_ERR, "%s: malloc failure", progname);
|
|
goto out_free;
|
|
}
|
|
break;
|
|
#ifdef ENABLE_ALL_OPTIONS
|
|
case 'o':
|
|
if (oemtype) {
|
|
free(oemtype);
|
|
oemtype = NULL;
|
|
}
|
|
oemtype = strdup(optarg);
|
|
if (oemtype == NULL) {
|
|
lprintf(LOG_ERR, "%s: malloc failure", progname);
|
|
goto out_free;
|
|
}
|
|
if (strncmp(oemtype, "list", 4) == 0 ||
|
|
strncmp(oemtype, "help", 4) == 0) {
|
|
ipmi_oem_print();
|
|
rc = 0;
|
|
goto out_free;
|
|
}
|
|
break;
|
|
case 'g':
|
|
/* backwards compatible oem hack */
|
|
if (oemtype) {
|
|
free(oemtype);
|
|
oemtype = NULL;
|
|
}
|
|
oemtype = strdup("intelwv2");
|
|
break;
|
|
case 's':
|
|
/* backwards compatible oem hack */
|
|
if (oemtype) {
|
|
free(oemtype);
|
|
oemtype = NULL;
|
|
}
|
|
oemtype = strdup("supermicro");
|
|
break;
|
|
case 'P':
|
|
if (password) {
|
|
free(password);
|
|
password = NULL;
|
|
}
|
|
password = strdup(optarg);
|
|
if (password == NULL) {
|
|
lprintf(LOG_ERR, "%s: malloc failure", progname);
|
|
goto out_free;
|
|
}
|
|
|
|
/* Prevent password snooping with ps */
|
|
i = strlen(optarg);
|
|
memset(optarg, 'X', i);
|
|
break;
|
|
case 'E':
|
|
if ((tmp_env = getenv("IPMITOOL_PASSWORD"))) {
|
|
if (password) {
|
|
free(password);
|
|
password = NULL;
|
|
}
|
|
password = strdup(tmp_env);
|
|
if (password == NULL) {
|
|
lprintf(LOG_ERR, "%s: malloc failure", progname);
|
|
goto out_free;
|
|
}
|
|
}
|
|
else if ((tmp_env = getenv("IPMI_PASSWORD"))) {
|
|
if (password) {
|
|
free(password);
|
|
password = NULL;
|
|
}
|
|
password = strdup(tmp_env);
|
|
if (password == NULL) {
|
|
lprintf(LOG_ERR, "%s: malloc failure", progname);
|
|
goto out_free;
|
|
}
|
|
}
|
|
else {
|
|
lprintf(LOG_WARN, "Unable to read password from environment");
|
|
}
|
|
break;
|
|
case 'L':
|
|
i = strlen(optarg);
|
|
if ((i > 0) && (optarg[i-1] == '+')) {
|
|
lookupbit = 0;
|
|
optarg[i-1] = 0;
|
|
}
|
|
privlvl = str2val(optarg, ipmi_privlvl_vals);
|
|
if (privlvl == 0xFF) {
|
|
lprintf(LOG_WARN, "Invalid privilege level %s", optarg);
|
|
}
|
|
break;
|
|
case 'A':
|
|
authtype = str2val(optarg, ipmi_authtype_session_vals);
|
|
break;
|
|
case 't':
|
|
if (str2uchar(optarg, &target_addr) != 0) {
|
|
lprintf(LOG_ERR, "Invalid parameter given or out of range for '-t'.");
|
|
rc = -1;
|
|
goto out_free;
|
|
}
|
|
break;
|
|
case 'b':
|
|
if (str2uchar(optarg, &target_channel) != 0) {
|
|
lprintf(LOG_ERR, "Invalid parameter given or out of range for '-b'.");
|
|
rc = -1;
|
|
goto out_free;
|
|
}
|
|
break;
|
|
case 'T':
|
|
if (str2uchar(optarg, &transit_addr) != 0) {
|
|
lprintf(LOG_ERR, "Invalid parameter given or out of range for '-T'.");
|
|
rc = -1;
|
|
goto out_free;
|
|
}
|
|
break;
|
|
case 'B':
|
|
if (str2uchar(optarg, &transit_channel) != 0) {
|
|
lprintf(LOG_ERR, "Invalid parameter given or out of range for '-B'.");
|
|
rc = -1;
|
|
goto out_free;
|
|
}
|
|
break;
|
|
case 'l':
|
|
if (str2uchar(optarg, &target_lun) != 0) {
|
|
lprintf(LOG_ERR, "Invalid parameter given or out of range for '-l'.");
|
|
rc = 1;
|
|
goto out_free;
|
|
}
|
|
break;
|
|
case 'm':
|
|
if (str2uchar(optarg, &arg_addr) != 0) {
|
|
lprintf(LOG_ERR, "Invalid parameter given or out of range for '-m'.");
|
|
rc = -1;
|
|
goto out_free;
|
|
}
|
|
break;
|
|
case 'e':
|
|
sol_escape_char = optarg[0];
|
|
break;
|
|
case 'O':
|
|
if (seloem) {
|
|
free(seloem);
|
|
seloem = NULL;
|
|
}
|
|
seloem = strdup(optarg);
|
|
if (seloem == NULL) {
|
|
lprintf(LOG_ERR, "%s: malloc failure", progname);
|
|
goto out_free;
|
|
}
|
|
break;
|
|
case 'z':
|
|
if (str2ushort(optarg, &my_long_packet_size) != 0) {
|
|
lprintf(LOG_ERR, "Invalid parameter given or out of range for '-z'.");
|
|
rc = -1;
|
|
goto out_free;
|
|
}
|
|
break;
|
|
/* Retry and Timeout */
|
|
case 'R':
|
|
if (str2int(optarg, &retry) != 0 || retry < 0) {
|
|
lprintf(LOG_ERR, "Invalid parameter given or out of range for '-R'.");
|
|
rc = -1;
|
|
goto out_free;
|
|
}
|
|
break;
|
|
case 'N':
|
|
if (str2uint(optarg, &timeout) != 0) {
|
|
lprintf(LOG_ERR, "Invalid parameter given or out of range for '-N'.");
|
|
rc = -1;
|
|
goto out_free;
|
|
}
|
|
break;
|
|
#endif
|
|
default:
|
|
ipmi_option_usage(progname, cmdlist, intflist);
|
|
goto out_free;
|
|
}
|
|
}
|
|
|
|
/* check for command before doing anything */
|
|
if (argc-optind > 0 &&
|
|
strncmp(argv[optind], "help", 4) == 0) {
|
|
ipmi_cmd_print(cmdlist);
|
|
rc = 0;
|
|
goto out_free;
|
|
}
|
|
|
|
/*
|
|
* If the user has specified a hostname (-H option)
|
|
* then this is a remote access session.
|
|
*
|
|
* If no password was specified by any other method
|
|
* and the authtype was not explicitly set to NONE
|
|
* then prompt the user.
|
|
*/
|
|
if (hostname != NULL && password == NULL &&
|
|
(authtype != IPMI_SESSION_AUTHTYPE_NONE || authtype < 0)) {
|
|
#ifdef HAVE_GETPASSPHRASE
|
|
tmp_pass = getpassphrase("Password: ");
|
|
#else
|
|
tmp_pass = getpass("Password: ");
|
|
#endif
|
|
if (tmp_pass != NULL) {
|
|
password = strdup(tmp_pass);
|
|
tmp_pass = NULL;
|
|
if (password == NULL) {
|
|
lprintf(LOG_ERR, "%s: malloc failure", progname);
|
|
goto out_free;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* if no interface was specified but a
|
|
* hostname was then use LAN by default
|
|
* otherwise the default is hardcoded
|
|
* to use the first entry in the list
|
|
*/
|
|
if (intfname == NULL && hostname != NULL) {
|
|
intfname = strdup("lan");
|
|
if (intfname == NULL) {
|
|
lprintf(LOG_ERR, "%s: malloc failure", progname);
|
|
goto out_free;
|
|
}
|
|
}
|
|
|
|
if (password != NULL && intfname != NULL) {
|
|
if (strcmp(intfname, "lan") == 0 && strlen(password) > 16) {
|
|
lprintf(LOG_ERR, "%s: password is longer than 16 bytes.", intfname);
|
|
rc = -1;
|
|
goto out_free;
|
|
} else if (strcmp(intfname, "lanplus") == 0 && strlen(password) > 20) {
|
|
lprintf(LOG_ERR, "%s: password is longer than 20 bytes.", intfname);
|
|
rc = -1;
|
|
goto out_free;
|
|
}
|
|
} /* if (password != NULL && intfname != NULL) */
|
|
|
|
/* load interface */
|
|
ipmi_main_intf = ipmi_intf_load(intfname);
|
|
if (ipmi_main_intf == NULL) {
|
|
lprintf(LOG_ERR, "Error loading interface %s", intfname);
|
|
goto out_free;
|
|
}
|
|
|
|
/* setup log */
|
|
log_init(progname, 0, verbose);
|
|
|
|
/* run OEM setup if found */
|
|
if (oemtype != NULL &&
|
|
ipmi_oem_setup(ipmi_main_intf, oemtype) < 0) {
|
|
lprintf(LOG_ERR, "OEM setup for \"%s\" failed", oemtype);
|
|
goto out_free;
|
|
}
|
|
|
|
/* set session variables */
|
|
if (hostname != NULL)
|
|
ipmi_intf_session_set_hostname(ipmi_main_intf, hostname);
|
|
if (username != NULL)
|
|
ipmi_intf_session_set_username(ipmi_main_intf, username);
|
|
if (password != NULL)
|
|
ipmi_intf_session_set_password(ipmi_main_intf, password);
|
|
if (kgkey != NULL)
|
|
ipmi_intf_session_set_kgkey(ipmi_main_intf, kgkey);
|
|
if (port > 0)
|
|
ipmi_intf_session_set_port(ipmi_main_intf, port);
|
|
if (authtype >= 0)
|
|
ipmi_intf_session_set_authtype(ipmi_main_intf, (uint8_t)authtype);
|
|
if (privlvl > 0)
|
|
ipmi_intf_session_set_privlvl(ipmi_main_intf, (uint8_t)privlvl);
|
|
else
|
|
ipmi_intf_session_set_privlvl(ipmi_main_intf,
|
|
IPMI_SESSION_PRIV_ADMIN); /* default */
|
|
/* Adding retry and timeout for interface that support it */
|
|
if (retry > 0)
|
|
ipmi_intf_session_set_retry(ipmi_main_intf, retry);
|
|
if (timeout > 0)
|
|
ipmi_intf_session_set_timeout(ipmi_main_intf, timeout);
|
|
|
|
ipmi_intf_session_set_lookupbit(ipmi_main_intf, lookupbit);
|
|
ipmi_intf_session_set_sol_escape_char(ipmi_main_intf, sol_escape_char);
|
|
ipmi_intf_session_set_cipher_suite_id(ipmi_main_intf, cipher_suite_id);
|
|
|
|
ipmi_main_intf->devnum = devnum;
|
|
|
|
/* setup device file if given */
|
|
ipmi_main_intf->devfile = devfile;
|
|
|
|
/* Open the interface with the specified or default IPMB address */
|
|
ipmi_main_intf->my_addr = arg_addr ? arg_addr : IPMI_BMC_SLAVE_ADDR;
|
|
if (ipmi_main_intf->open != NULL) {
|
|
if (ipmi_main_intf->open(ipmi_main_intf) < 0) {
|
|
goto out_free;
|
|
}
|
|
}
|
|
/*
|
|
* Attempt picmg discovery of the actual interface address unless
|
|
* the users specified an address.
|
|
* Address specification always overrides discovery
|
|
*/
|
|
if (picmg_discover(ipmi_main_intf) && !arg_addr) {
|
|
lprintf(LOG_DEBUG, "Running PICMG Get Address Info");
|
|
addr = ipmi_picmg_ipmb_address(ipmi_main_intf);
|
|
lprintf(LOG_INFO, "Discovered IPMB-0 address 0x%x", addr);
|
|
}
|
|
|
|
/*
|
|
* If we discovered the ipmb address and it is not the same as what we
|
|
* used for open, Set the discovered IPMB address as my address if the
|
|
* interface supports it.
|
|
*/
|
|
if (addr != 0 && addr != ipmi_main_intf->my_addr &&
|
|
ipmi_main_intf->set_my_addr) {
|
|
/*
|
|
* Only set the interface address on interfaces which support
|
|
* it
|
|
*/
|
|
(void) ipmi_main_intf->set_my_addr(ipmi_main_intf, addr);
|
|
}
|
|
|
|
/* If bridging addresses are specified, handle them */
|
|
if (target_addr > 0) {
|
|
ipmi_main_intf->target_addr = target_addr;
|
|
ipmi_main_intf->target_lun = target_lun ;
|
|
ipmi_main_intf->target_channel = target_channel ;
|
|
}
|
|
if (transit_addr > 0) {
|
|
/* sanity check, transit makes no sense without a target */
|
|
if ((transit_addr != 0 || transit_channel != 0) &&
|
|
ipmi_main_intf->target_addr == 0) {
|
|
lprintf(LOG_ERR,
|
|
"Transit address/channel %#x/%#x ignored. "
|
|
"Target address must be specified!",
|
|
transit_addr, transit_channel);
|
|
goto out_free;
|
|
}
|
|
|
|
ipmi_main_intf->transit_addr = transit_addr;
|
|
ipmi_main_intf->transit_channel = transit_channel;
|
|
}
|
|
if (ipmi_main_intf->target_addr > 0) {
|
|
/* must be admin level to do this over lan */
|
|
ipmi_intf_session_set_privlvl(ipmi_main_intf, IPMI_SESSION_PRIV_ADMIN);
|
|
/* Get the ipmb address of the targeted entity */
|
|
ipmi_main_intf->target_ipmb_addr =
|
|
ipmi_picmg_ipmb_address(ipmi_main_intf);
|
|
lprintf(LOG_DEBUG, "Specified addressing Target %#x:%#x Transit %#x:%#x",
|
|
ipmi_main_intf->target_addr,
|
|
ipmi_main_intf->target_channel,
|
|
ipmi_main_intf->transit_addr,
|
|
ipmi_main_intf->transit_channel);
|
|
if (ipmi_main_intf->target_ipmb_addr) {
|
|
lprintf(LOG_INFO, "Discovered Target IPMB-0 address %#x",
|
|
ipmi_main_intf->target_ipmb_addr);
|
|
}
|
|
}
|
|
|
|
lprintf(LOG_DEBUG, "Interface address: my_addr %#x "
|
|
"transit %#x:%#x target %#x:%#x "
|
|
"ipmb_target %#x\n",
|
|
ipmi_main_intf->my_addr,
|
|
ipmi_main_intf->transit_addr,
|
|
ipmi_main_intf->transit_channel,
|
|
ipmi_main_intf->target_addr,
|
|
ipmi_main_intf->target_channel,
|
|
ipmi_main_intf->target_ipmb_addr);
|
|
|
|
/* parse local SDR cache if given */
|
|
if (sdrcache != NULL) {
|
|
ipmi_sdr_list_cache_fromfile(ipmi_main_intf, sdrcache);
|
|
}
|
|
/* Parse SEL OEM file if given */
|
|
if (seloem != NULL) {
|
|
ipmi_sel_oem_init(seloem);
|
|
}
|
|
|
|
/* Enable Big Buffer when requested */
|
|
if ( my_long_packet_size != 0 ) {
|
|
/* Enable Big Buffer when requested */
|
|
if (!ipmi_oem_active(ipmi_main_intf, "kontron") ||
|
|
ipmi_kontronoem_set_large_buffer(ipmi_main_intf,
|
|
my_long_packet_size ) == 0) {
|
|
printf("Setting large buffer to %i\n", my_long_packet_size);
|
|
my_long_packet_set = 1;
|
|
ipmi_intf_set_max_request_data_size(ipmi_main_intf,
|
|
my_long_packet_size);
|
|
}
|
|
}
|
|
|
|
ipmi_main_intf->cmdlist = cmdlist;
|
|
|
|
/* now we finally run the command */
|
|
if (argc-optind > 0)
|
|
rc = ipmi_cmd_run(ipmi_main_intf, argv[optind], argc-optind-1,
|
|
&(argv[optind+1]));
|
|
else
|
|
rc = ipmi_cmd_run(ipmi_main_intf, NULL, 0, NULL);
|
|
|
|
if (my_long_packet_set == 1) {
|
|
if (ipmi_oem_active(ipmi_main_intf, "kontron")) {
|
|
/* Restore defaults */
|
|
ipmi_kontronoem_set_large_buffer( ipmi_main_intf, 0 );
|
|
}
|
|
}
|
|
|
|
/* clean repository caches */
|
|
ipmi_cleanup(ipmi_main_intf);
|
|
|
|
/* call interface close function if available */
|
|
if (ipmi_main_intf->opened > 0 && ipmi_main_intf->close != NULL)
|
|
ipmi_main_intf->close(ipmi_main_intf);
|
|
|
|
out_free:
|
|
log_halt();
|
|
|
|
if (intfname != NULL) {
|
|
free(intfname);
|
|
intfname = NULL;
|
|
}
|
|
if (hostname != NULL) {
|
|
free(hostname);
|
|
hostname = NULL;
|
|
}
|
|
if (username != NULL) {
|
|
free(username);
|
|
username = NULL;
|
|
}
|
|
if (password != NULL) {
|
|
free(password);
|
|
password = NULL;
|
|
}
|
|
if (oemtype != NULL) {
|
|
free(oemtype);
|
|
oemtype = NULL;
|
|
}
|
|
if (seloem != NULL) {
|
|
free(seloem);
|
|
seloem = NULL;
|
|
}
|
|
if (kgkey != NULL) {
|
|
free(kgkey);
|
|
kgkey = NULL;
|
|
}
|
|
if (sdrcache != NULL) {
|
|
free(sdrcache);
|
|
sdrcache = NULL;
|
|
}
|
|
if (devfile) {
|
|
free(devfile);
|
|
devfile = NULL;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|