diff options
author | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2014-07-23 15:03:01 +0200 |
---|---|---|
committer | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2014-07-23 15:03:01 +0200 |
commit | 777af8a8761d05c30588abec7444b143fe7393f0 (patch) | |
tree | 5a135c37eaa9ac94772819a28ce5beedd18e5c4a /lib/ipmi_main.c | |
parent | c3445516ecd58e97de483cf4b7fafcc1104890d7 (diff) | |
parent | b32d92e890caac903491116e9d817aa780c0323b (diff) |
Merge tag 'upstream/1.8.14'
Upstream version 1.8.14
Diffstat (limited to 'lib/ipmi_main.c')
-rw-r--r-- | lib/ipmi_main.c | 1063 |
1 files changed, 1063 insertions, 0 deletions
diff --git a/lib/ipmi_main.c b/lib/ipmi_main.c new file mode 100644 index 0000000..14ca183 --- /dev/null +++ b/lib/ipmi_main.c @@ -0,0 +1,1063 @@ +/* + * 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; +} + + |