From 2eeceac233af61877d8a8397cf0dd8fd66b92f34 Mon Sep 17 00:00:00 2001 From: Jeremy Ellington Date: Tue, 3 Aug 2004 18:40:09 +0000 Subject: [PATCH] Added user subcommand --- ipmitool/include/ipmitool/Makefile.am | 2 +- ipmitool/include/ipmitool/ipmi_user.h | 93 ++++ ipmitool/lib/Makefile.am | 2 +- ipmitool/lib/ipmi_user.c | 610 ++++++++++++++++++++++++++ 4 files changed, 705 insertions(+), 2 deletions(-) create mode 100644 ipmitool/include/ipmitool/ipmi_user.h create mode 100644 ipmitool/lib/ipmi_user.c diff --git a/ipmitool/include/ipmitool/Makefile.am b/ipmitool/include/ipmitool/Makefile.am index ac5697b..b86ef9c 100644 --- a/ipmitool/include/ipmitool/Makefile.am +++ b/ipmitool/include/ipmitool/Makefile.am @@ -40,5 +40,5 @@ noinst_HEADERS = bswap.h helper.h ipmi.h ipmi_intf.h \ ipmi_chassis.h ipmi_entity.h ipmi_fru.h ipmi_lanp.h \ ipmi_sdr.h ipmi_sel.h ipmi_sol.h ipmi_bmc.h \ ipmi_channel.h ipmi_sensor.h ipmi_event.h ipmi_session.h \ - ipmi_strings.h ipmi_constants.h ipmi_isol.h + ipmi_strings.h ipmi_constants.h ipmi_isol.h ipmi_user.h diff --git a/ipmitool/include/ipmitool/ipmi_user.h b/ipmitool/include/ipmitool/ipmi_user.h new file mode 100644 index 0000000..eb58975 --- /dev/null +++ b/ipmitool/include/ipmitool/ipmi_user.h @@ -0,0 +1,93 @@ +/* + * 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. + * + * You acknowledge that this software is not designed or intended for use + * in the design, construction, operation or maintenance of any nuclear + * facility. + */ + +#ifndef IPMI_USER_H +#define IPMI_USER_H + +#if HAVE_CONFIG_H +# include +#endif +#include + + +/* + * The GET USER ACCESS response from table 22-32 of the IMPI v2.0 spec + */ +struct user_access_rsp { +#if WORDS_BIGENDIAN + unsigned char __reserved1 : 2; + unsigned char maximum_ids : 6; +#else + unsigned char maximum_ids : 6; + unsigned char __reserved1 : 2; +#endif + +#if WORDS_BIGENDIAN + unsigned char __reserved2 : 2; + unsigned char enabled_user_count : 6; +#else + unsigned char enabled_user_count : 6; + unsigned char __reserved2 : 2; +#endif + +#if WORDS_BIGENDIAN + unsigned char __reserved3 : 2; + unsigned char fixed_name_count : 6; +#else + unsigned char fixed_name_count : 6; + unsigned char __reserved3 : 2; +#endif + +#if WORDS_BIGENDIAN + unsigned char __reserved4 : 1; + unsigned char no_callin_access : 1; + unsigned char link_auth_access : 1; + unsigned char ipmi_messaging_access : 1; + unsigned char channel_privilege_limit : 4; +#else + unsigned char channel_privilege_limit : 4; + unsigned char ipmi_messaging_access : 1; + unsigned char link_auth_access : 1; + unsigned char no_callin_access : 1; + unsigned char __reserved4 : 1; +#endif +} __attribute__ ((packed)); + + + +int ipmi_user_main(struct ipmi_intf *, int, char **); + +#endif /* IPMI_USER_H */ diff --git a/ipmitool/lib/Makefile.am b/ipmitool/lib/Makefile.am index 20ee620..62f132a 100644 --- a/ipmitool/lib/Makefile.am +++ b/ipmitool/lib/Makefile.am @@ -38,7 +38,7 @@ MAINTAINERCLEANFILES = Makefile.in noinst_LTLIBRARIES = libipmitool.la libipmitool_la_SOURCES = helper.c ipmi_sdr.c ipmi_sel.c ipmi_sol.c ipmi_isol.c ipmi_lanp.c \ ipmi_fru.c ipmi_chassis.c ipmi_bmc.c dimm_spd.c ipmi_sensor.c \ - ipmi_channel.c ipmi_event.c ipmi_session.c ipmi_strings.c + ipmi_channel.c ipmi_event.c ipmi_session.c ipmi_strings.c ipmi_user.c libipmitool_la_LDFLAGS = -export-dynamic libipmitool_la_LIBADD = -lm libipmitool_la_DEPENDENCIES = diff --git a/ipmitool/lib/ipmi_user.c b/ipmitool/lib/ipmi_user.c new file mode 100644 index 0000000..921a48c --- /dev/null +++ b/ipmitool/lib/ipmi_user.c @@ -0,0 +1,610 @@ +/* + * 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. + * + * You acknowledge that this software is not designed or intended for use + * in the design, construction, operation or maintenance of any nuclear + * facility. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +extern int verbose; +extern int csv_output; + + +#define IPMI_PASSWORD_DISABLE_USER 0x00 +#define IPMI_PASSWORD_ENABLE_USER 0x01 +#define IPMI_PASSWORD_SET_PASSWORD 0x02 +#define IPMI_PASSWORD_TEST_PASSWORD 0x03 + + +/* + * ipmi_get_user_access + * + * param intf [in] + * param channel_number [in] + * param user_id [in] + * param user_access [out] + * + * return 0 on succes + * 1 on failure + */ +static int +ipmi_get_user_access( + struct ipmi_intf * intf, + unsigned char channel_number, + unsigned char user_id, + struct user_access_rsp * user_access) + +{ + struct ipmi_rs * rsp; + struct ipmi_rq req; + unsigned char msg_data[2]; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; /* 0x06 */ + req.msg.cmd = IPMI_GET_USER_ACCESS; /* 0x44 */ + req.msg.data = msg_data; + req.msg.data_len = 2; + + + /* The channel number will remain constant throughout this function */ + msg_data[0] = channel_number; + msg_data[1] = user_id; + + rsp = intf->sendrecv(intf, &req); + + if (!rsp || rsp->ccode) + { + printf("Error:%x Get User Access Command (user 0x%x)\n", + rsp ? rsp->ccode : 0, msg_data[1]); + return -1; + } + + memcpy(user_access, + rsp->data, + sizeof(struct user_access_rsp)); + + return 0; +} + + + +/* + * ipmi_get_user_name + * + * param intf [in] + * param channel_number [in] + * param user_id [in] + * param user_name [out] + * + * return 0 on succes + * 1 on failure + */ +static int +ipmi_get_user_name( + struct ipmi_intf * intf, + unsigned char user_id, + char * user_name) + +{ + struct ipmi_rs * rsp; + struct ipmi_rq req; + unsigned char msg_data[1]; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; /* 0x06 */ + req.msg.cmd = IPMI_GET_USER_NAME; /* 0x45 */ + req.msg.data = msg_data; + req.msg.data_len = 1; + + msg_data[0] = user_id; + + rsp = intf->sendrecv(intf, &req); + + if (!rsp || rsp->ccode) + { + printf("Error:%x Get User Name Command (user 0x%x)\n", + rsp ? rsp->ccode : 0, msg_data[0]); + return -1; + } + + memcpy(user_name, rsp->data, 16); + + return 0; +} + + + + +static void +dump_user_access( + unsigned char user_id, + const char * user_name, + struct user_access_rsp * user_access) +{ + static int printed_header = 0; + + if (! printed_header) + { + printf("ID Name Callin Link Auth IPMI Msg " + "Channel Priv Limit\n"); + printed_header = 1; + } + + + printf("%-4d%-17s%-8s%-11s%-11s%-s\n", + user_id, + user_name, + user_access->no_callin_access? "false": "true ", + user_access->link_auth_access? "true ": "false", + user_access->ipmi_messaging_access? "true ": "false", + val2str(user_access->channel_privilege_limit, + ipmi_privlvl_vals)); +} + + + +static void +dump_user_access_csv( + unsigned char user_id, + const char * user_name, + struct user_access_rsp * user_access) +{ + printf("%d,%s,%s,%s,%s,%s\n", + user_id, + user_name, + user_access->no_callin_access? "false": "true", + user_access->link_auth_access? "true": "false", + user_access->ipmi_messaging_access? "true": "false", + val2str(user_access->channel_privilege_limit, + ipmi_privlvl_vals)); +} + + + +static int +ipmi_print_user_list( + struct ipmi_intf * intf, + unsigned char channel_number) +{ + /* This is where you were! */ + char user_name[17]; + struct user_access_rsp user_access; + unsigned char current_user_id = 1; + + + do + { + if (ipmi_get_user_access(intf, + channel_number, + current_user_id, + &user_access)) + return -1; + + + if (ipmi_get_user_name(intf, + current_user_id, + user_name)) + return -1; + + + if ((current_user_id == 0) || + user_access.link_auth_access || + user_access.ipmi_messaging_access || + strcmp("", user_name)) + { + if (csv_output) + dump_user_access_csv(current_user_id, user_name, &user_access); + else + dump_user_access(current_user_id, user_name, &user_access); + } + + + ++current_user_id; + } while((current_user_id < user_access.maximum_ids) && + (current_user_id < 63)); /* Absolute maximum allowed by spec */ + + + return 0; +} + + + +static int +ipmi_print_user_summary( + struct ipmi_intf * intf, + unsigned char channel_number) +{ + struct user_access_rsp user_access; + + if (ipmi_get_user_access(intf, + channel_number, + 1, + &user_access)) + return -1; + + if (csv_output) + { + printf("%d,%d,%d\n", + user_access.maximum_ids, + user_access.enabled_user_count, + user_access.fixed_name_count); + } + else + { + printf("Maximum IDs : %d\n", + user_access.maximum_ids); + printf("Enabled User Count : %d\n", + user_access.enabled_user_count); + printf("Fixed Name Count : %d\n", + user_access.fixed_name_count); + } + + return 0; +} + + + +/* + * ipmi_user_set_username + */ +static int +ipmi_user_set_username( + struct ipmi_intf * intf, + unsigned char user_id, + const char * name) +{ + struct ipmi_rs * rsp; + struct ipmi_rq req; + unsigned char msg_data[17]; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; /* 0x06 */ + req.msg.cmd = IPMI_SET_USER_NAME; /* 0x45 */ + req.msg.data = msg_data; + req.msg.data_len = 17; + + + /* The channel number will remain constant throughout this function */ + msg_data[0] = user_id; + memset(msg_data + 1, 0, 16); + strcpy(msg_data + 1, name); + + rsp = intf->sendrecv(intf, &req); + + if (!rsp || rsp->ccode) + { + printf("Error:%x Set User Name Command\n", + rsp ? rsp->ccode : 0); + return -1; + } + + + return 0; +} + + + +/* + * ipmi_user_set_password + * + * This function is responsible for 4 things + * Enabling/Disabling users + * Setting/Testing passwords + */ +static int +ipmi_user_set_password( + struct ipmi_intf * intf, + unsigned char user_id, + unsigned char operation, + const char * password) +{ + struct ipmi_rs * rsp; + struct ipmi_rq req; + unsigned char msg_data[18]; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; /* 0x06 */ + req.msg.cmd = IPMI_SET_USER_PASSWORD; /* 0x47 */ + req.msg.data = msg_data; + req.msg.data_len = 18; + + + /* The channel number will remain constant throughout this function */ + msg_data[0] = user_id; + msg_data[1] = operation; + + memset(msg_data + 2, 0, 16); + + if (password) + strcpy(msg_data + 2, password); + + rsp = intf->sendrecv(intf, &req); + + if (!rsp || rsp->ccode) + { + printf("Error:%x Set User Password Command\n", + rsp ? rsp->ccode : 0); + return -1; + } + + + return 0; +} + + + +/* + * print_user_usage + */ +void +print_user_usage() +{ + printf("\n"); + printf("User Commands: summary []\n"); + printf(" list []\n"); + printf(" set name \n"); + printf(" set password []\n"); + printf(" disable []\n"); + printf(" enable []\n"); + + printf("\n"); +} + + + +/* + * + */ +void +print_user_set_usage() +{ + printf("\nUser set parameters and values: \n\n"); + printf(" name \n"); + printf(" password \n"); + printf("\n"); +} + + +const char * +ipmi_user_build_password_prompt(unsigned char user_id) +{ + static char prompt[128]; + sprintf(prompt, "Password for user %d: ", user_id); + return prompt; +} + + +/* + * ipmi_user_main + * + * Upon entry to this function argv should contain our arguments + * specific to this subcommand + */ +int +ipmi_user_main(struct ipmi_intf * intf, int argc, char ** argv) +{ + int retval = 0; + + /* + * Help + */ + if (!argc || !strncmp(argv[0], "help", 4)) + print_user_usage(); + + /* + * Summary + */ + else if (!strncmp(argv[0], "summary", 7)) { + unsigned char channel; + + if (argc == 1) + channel = 0x0E; /* Ask about the current channel */ + else if (argc == 2) + channel = (unsigned char)strtol(argv[1], NULL, 0); + else + { + print_user_usage(); + return -1; + } + + retval = ipmi_print_user_summary(intf, channel); + } + + + /* + * List + */ + else if (!strncmp(argv[0], "list", 4)) { + unsigned char channel; + + if (argc == 1) + channel = 0x0E; /* Ask about the current channel */ + else if (argc == 2) + channel = (unsigned char)strtol(argv[1], NULL, 0); + else + { + print_user_usage(); + return -1; + } + + retval = ipmi_print_user_list(intf, channel); + } + + + /* + * Set + */ + else if (!strncmp(argv[0], "set", 3)) + { + /* + * Set Password + */ + if ((argc >= 3) && + (! strcmp("password", argv[1]))) + { + char * password; + unsigned char user_id = (unsigned char)strtol(argv[2], + NULL, + 0); + if (! user_id) + { + printf("Error. Invalid user ID: %d\n", user_id); + return -1; + } + + + if (argc == 3) + { + /* We need to prompt for a password */ + + char * tmp; + const char * password_prompt = + ipmi_user_build_password_prompt(user_id); + +#ifdef HAVE_GETPASSPHRASE + if ((tmp = getpassphrase (password_prompt))) +#else + if ((tmp = (char*)getpass (password_prompt))) +#endif + { + password = strdup(tmp); + +#ifdef HAVE_GETPASSPHRASE + if ((tmp = getpassphrase (password_prompt))) +#else + if ((tmp = (char*)getpass (password_prompt))) +#endif + { + if (strcmp(password, tmp)) + { + printf("Error. Passwords to not match.\n"); + return -1; + } + } + } + } + + + retval = ipmi_user_set_password(intf, + user_id, + IPMI_PASSWORD_SET_PASSWORD, + argc == 4? argv[3]: password); + } + + + /* + * Set Name + */ + else if ((argc >= 2) && + (! strcmp("name", argv[1]))) + { + if (argc != 4) + { + print_user_set_usage(); + return -1; + } + + retval = ipmi_user_set_username(intf, + (unsigned char)strtol(argv[2], + NULL, + 0), + argv[3]); + } + else + { + print_user_set_usage(); + return -1; + } + } + + + /* + * Disable / Enable + */ + else if ((!strncmp(argv[0], "disable", 7)) || + (!strncmp(argv[0], "enable", 6))) + { + unsigned char user_id; + unsigned char operation; + char null_password[16]; /* Not used, but required */ + + memset(null_password, 0, sizeof(null_password)); + + if (argc != 2) + { + print_user_usage(); + return -1; + } + + user_id = (unsigned char)strtol(argv[1], + NULL, + 0); + if (! user_id) + { + printf("Error. Invalid user ID: %d\n", user_id); + return -1; + } + + + operation = (!strncmp(argv[0], "disable", 7))? + IPMI_PASSWORD_DISABLE_USER: IPMI_PASSWORD_ENABLE_USER; + + retval = ipmi_user_set_password(intf, + user_id, + operation, + null_password); + } + + + else + { + print_user_usage(); + retval = -1; + } + + return retval; +}