15345Seschrock /* 25345Seschrock * CDDL HEADER START 35345Seschrock * 45345Seschrock * The contents of this file are subject to the terms of the 55345Seschrock * Common Development and Distribution License (the "License"). 65345Seschrock * You may not use this file except in compliance with the License. 75345Seschrock * 85345Seschrock * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 95345Seschrock * or http://www.opensolaris.org/os/licensing. 105345Seschrock * See the License for the specific language governing permissions 115345Seschrock * and limitations under the License. 125345Seschrock * 135345Seschrock * When distributing Covered Code, include this CDDL HEADER in each 145345Seschrock * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 155345Seschrock * If applicable, add the following below this CDDL HEADER, with the 165345Seschrock * fields enclosed by brackets "[]" replaced with your own identifying 175345Seschrock * information: Portions Copyright [yyyy] [name of copyright owner] 185345Seschrock * 195345Seschrock * CDDL HEADER END 205345Seschrock */ 215345Seschrock /* 22*6070Srobj * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 235345Seschrock * Use is subject to license terms. 245345Seschrock */ 255345Seschrock 265345Seschrock #pragma ident "%Z%%M% %I% %E% SMI" 275345Seschrock 285345Seschrock #include <libipmi.h> 295345Seschrock #include <string.h> 305345Seschrock 315345Seschrock #include "ipmi_impl.h" 325345Seschrock 33*6070Srobj typedef struct ipmi_user_impl { 34*6070Srobj ipmi_list_t iu_list; 35*6070Srobj ipmi_user_t iu_user; 36*6070Srobj } ipmi_user_impl_t; 37*6070Srobj 385345Seschrock /* 395345Seschrock * Get User Access. See section 22.27. 405345Seschrock * 415345Seschrock * See libipmi.h for a complete description of IPMI reference material. 425345Seschrock */ 435345Seschrock 445345Seschrock typedef struct ipmi_get_user_access_req { 455621Seschrock DECL_BITFIELD2( 465621Seschrock igua_channel :4, 475621Seschrock __reserved1 :4); 485621Seschrock DECL_BITFIELD2( 495621Seschrock igua_uid :2, 505621Seschrock __reserved2 :6); 515345Seschrock } ipmi_get_user_access_req_t; 525345Seschrock 535345Seschrock #define IPMI_CMD_GET_USER_ACCESS 0x44 545345Seschrock 555345Seschrock typedef struct ipmi_get_user_access { 565621Seschrock DECL_BITFIELD2( 575621Seschrock igua_max_uid :4, 585621Seschrock __reserved1 :4); 595621Seschrock DECL_BITFIELD2( 605621Seschrock igua_enable_status :4, 615621Seschrock igua_enabled_uid :4); 625621Seschrock DECL_BITFIELD2( 635621Seschrock __reserved2 :4, 645621Seschrock igua_fixed_uid :4); 655621Seschrock DECL_BITFIELD5( 665621Seschrock __reserved3 :1, 675621Seschrock igua_only_callback :1, 685621Seschrock igua_link_auth_enable :1, 695621Seschrock igua_ipmi_msg_enable :1, 705621Seschrock igua_privilege_level :4); 715345Seschrock } ipmi_get_user_access_t; 725345Seschrock 735345Seschrock #define IPMI_USER_ENABLE_UNSPECIFIED 0x00 745345Seschrock #define IPMI_USER_ENABLE_SETPASSWD 0x01 755345Seschrock #define IPMI_USER_DISABLE_SETPASSWD 0x02 765345Seschrock 775345Seschrock #define IPMI_USER_CHANNEL_CURRENT 0xe 785345Seschrock 795345Seschrock /* 805345Seschrock * Get User Name. See section 22.29 815345Seschrock */ 825345Seschrock 835345Seschrock #define IPMI_CMD_GET_USER_NAME 0x46 845345Seschrock 855345Seschrock /* 865345Seschrock * Set User Password. See section 22.30 875345Seschrock */ 885345Seschrock 895345Seschrock #define IPMI_CMD_SET_USER_PASSWORD 0x47 905345Seschrock 915345Seschrock typedef struct ipmi_set_user_password { 925621Seschrock DECL_BITFIELD3( 935621Seschrock isup_uid :6, 945621Seschrock __reserved1 :1, 955621Seschrock isup_len20 :1); 965621Seschrock DECL_BITFIELD2( 975621Seschrock isup_op :2, 985621Seschrock __reserved2 :6); 995345Seschrock char isup_passwd[20]; 1005345Seschrock } ipmi_set_user_password_t; 1015345Seschrock 1025345Seschrock #define IPMI_PASSWORD_OP_DISABLE 0x0 1035345Seschrock #define IPMI_PASSWORD_OP_ENABLE 0x1 1045345Seschrock #define IPMI_PASSWORD_OP_SET 0x2 1055345Seschrock #define IPMI_PASSWORD_OP_TEST 0x3 1065345Seschrock 1075345Seschrock static ipmi_get_user_access_t * 1085345Seschrock ipmi_get_user_access(ipmi_handle_t *ihp, uint8_t channel, uint8_t uid) 1095345Seschrock { 1105345Seschrock ipmi_cmd_t cmd, *resp; 1115345Seschrock ipmi_get_user_access_req_t req = { 0 }; 1125345Seschrock 1135345Seschrock req.igua_channel = channel; 1145345Seschrock req.igua_uid = uid; 1155345Seschrock 1165345Seschrock cmd.ic_netfn = IPMI_NETFN_APP; 1175345Seschrock cmd.ic_cmd = IPMI_CMD_GET_USER_ACCESS; 1185345Seschrock cmd.ic_lun = 0; 1195345Seschrock cmd.ic_data = &req; 1205345Seschrock cmd.ic_dlen = sizeof (req); 1215345Seschrock 1225345Seschrock if ((resp = ipmi_send(ihp, &cmd)) == NULL) { 1235345Seschrock /* 1245345Seschrock * If sessions aren't supported on the current channel, some 1255345Seschrock * service processors (notably Sun's ILOM) will return an 1265345Seschrock * invalid request completion code (0xCC). For these SPs, we 1275345Seschrock * translate this to the more appropriate EIPMI_INVALID_COMMAND. 1285345Seschrock */ 1295345Seschrock if (ipmi_errno(ihp) == EIPMI_INVALID_REQUEST) 1305345Seschrock (void) ipmi_set_error(ihp, EIPMI_INVALID_COMMAND, 1315345Seschrock NULL); 1325345Seschrock return (NULL); 1335345Seschrock } 1345345Seschrock 1355345Seschrock if (resp->ic_dlen < sizeof (ipmi_get_user_access_t)) { 1365345Seschrock (void) ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL); 1375345Seschrock return (NULL); 1385345Seschrock } 1395345Seschrock 1405345Seschrock return (resp->ic_data); 1415345Seschrock } 1425345Seschrock 1435345Seschrock static const char * 1445345Seschrock ipmi_get_user_name(ipmi_handle_t *ihp, uint8_t uid) 1455345Seschrock { 1465345Seschrock ipmi_cmd_t cmd, *resp; 1475345Seschrock 1485345Seschrock cmd.ic_netfn = IPMI_NETFN_APP; 1495345Seschrock cmd.ic_cmd = IPMI_CMD_GET_USER_ACCESS; 1505345Seschrock cmd.ic_lun = 0; 1515345Seschrock cmd.ic_data = &uid; 1525345Seschrock cmd.ic_dlen = sizeof (uid); 1535345Seschrock 1545345Seschrock if ((resp = ipmi_send(ihp, &cmd)) == NULL) 1555345Seschrock return (NULL); 1565345Seschrock 1575345Seschrock if (resp->ic_dlen < 16) { 1585345Seschrock (void) ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL); 1595345Seschrock return (NULL); 1605345Seschrock } 1615345Seschrock 1625345Seschrock return (resp->ic_data); 1635345Seschrock } 1645345Seschrock 1655345Seschrock void 1665345Seschrock ipmi_user_clear(ipmi_handle_t *ihp) 1675345Seschrock { 168*6070Srobj ipmi_user_impl_t *uip; 1695345Seschrock 170*6070Srobj while ((uip = ipmi_list_next(&ihp->ih_users)) != NULL) { 171*6070Srobj ipmi_list_delete(&ihp->ih_users, uip); 172*6070Srobj ipmi_free(ihp, uip->iu_user.iu_name); 173*6070Srobj ipmi_free(ihp, uip); 1745345Seschrock } 1755345Seschrock } 1765345Seschrock 1775345Seschrock /* 1785345Seschrock * Returns user information in a well-defined structure. 1795345Seschrock */ 1805345Seschrock int 1815345Seschrock ipmi_user_iter(ipmi_handle_t *ihp, int (*func)(ipmi_user_t *, void *), 1825345Seschrock void *data) 1835345Seschrock { 1845345Seschrock ipmi_get_user_access_t *resp; 1855345Seschrock uint8_t i; 186*6070Srobj ipmi_user_impl_t *uip; 1875345Seschrock ipmi_user_t *up; 1885345Seschrock const char *name; 1895345Seschrock 1905345Seschrock ipmi_user_clear(ihp); 1915345Seschrock 1925345Seschrock /* 1935345Seschrock * First get the number of active users on the system by requesting the 1945345Seschrock * reserved user ID (0). 1955345Seschrock */ 1965345Seschrock if ((resp = ipmi_get_user_access(ihp, 1975345Seschrock IPMI_USER_CHANNEL_CURRENT, 0)) == NULL) 1985345Seschrock return (-1); 1995345Seschrock 2005345Seschrock for (i = 1; i <= resp->igua_max_uid; i++) { 2015345Seschrock if ((resp = ipmi_get_user_access(ihp, 2025345Seschrock IPMI_USER_CHANNEL_CURRENT, i)) == NULL) 2035345Seschrock return (-1); 2045345Seschrock 205*6070Srobj if ((uip = ipmi_zalloc(ihp, sizeof (ipmi_user_impl_t))) == NULL) 2065345Seschrock return (-1); 2075345Seschrock 208*6070Srobj up = &uip->iu_user; 209*6070Srobj 2105345Seschrock up->iu_enabled = resp->igua_enabled_uid; 2115345Seschrock up->iu_uid = i; 2125345Seschrock up->iu_ipmi_msg_enable = resp->igua_ipmi_msg_enable; 2135345Seschrock up->iu_link_auth_enable = resp->igua_link_auth_enable; 2145345Seschrock up->iu_priv = resp->igua_privilege_level; 215*6070Srobj 216*6070Srobj ipmi_list_append(&ihp->ih_users, uip); 2175345Seschrock 2185345Seschrock if ((name = ipmi_get_user_name(ihp, i)) == NULL) 2195345Seschrock return (-1); 2205345Seschrock 2215345Seschrock if (*name != '\0' && 2225345Seschrock (up->iu_name = ipmi_strdup(ihp, name)) == NULL) 2235345Seschrock return (-1); 2245345Seschrock } 2255345Seschrock 226*6070Srobj for (uip = ipmi_list_next(&ihp->ih_users); uip != NULL; 227*6070Srobj uip = ipmi_list_next(uip)) { 228*6070Srobj if (func(&uip->iu_user, data) != 0) 2295345Seschrock return (-1); 2305345Seschrock } 2315345Seschrock 2325345Seschrock return (0); 2335345Seschrock } 2345345Seschrock 2355345Seschrock typedef struct ipmi_user_cb { 2365345Seschrock const char *uic_name; 2375345Seschrock uint8_t uic_uid; 2385345Seschrock ipmi_user_t *uic_result; 2395345Seschrock } ipmi_user_cb_t; 2405345Seschrock 2415345Seschrock static int 2425345Seschrock ipmi_user_callback(ipmi_user_t *up, void *data) 2435345Seschrock { 2445345Seschrock ipmi_user_cb_t *cbp = data; 2455345Seschrock 2465345Seschrock if (cbp->uic_result != NULL) 2475345Seschrock return (0); 2485345Seschrock 2495345Seschrock if (up->iu_name) { 2505345Seschrock if (strcmp(up->iu_name, cbp->uic_name) == 0) 2515345Seschrock cbp->uic_result = up; 2525345Seschrock } else if (up->iu_uid == cbp->uic_uid) { 2535345Seschrock cbp->uic_result = up; 2545345Seschrock } 2555345Seschrock 2565345Seschrock return (0); 2575345Seschrock } 2585345Seschrock 2595345Seschrock ipmi_user_t * 2605345Seschrock ipmi_user_lookup_name(ipmi_handle_t *ihp, const char *name) 2615345Seschrock { 2625345Seschrock ipmi_user_cb_t cb = { 0 }; 2635345Seschrock 2645345Seschrock cb.uic_name = name; 2655345Seschrock cb.uic_result = NULL; 2665345Seschrock 2675345Seschrock if (ipmi_user_iter(ihp, ipmi_user_callback, &cb) != 0) 2685345Seschrock return (NULL); 2695345Seschrock 2705345Seschrock if (cb.uic_result == NULL) 2715345Seschrock (void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT, 2725345Seschrock "no such user"); 2735345Seschrock 2745345Seschrock return (cb.uic_result); 2755345Seschrock } 2765345Seschrock 2775345Seschrock ipmi_user_t * 2785345Seschrock ipmi_user_lookup_id(ipmi_handle_t *ihp, uint8_t uid) 2795345Seschrock { 2805345Seschrock ipmi_user_cb_t cb = { 0 }; 2815345Seschrock 2825345Seschrock cb.uic_uid = uid; 2835345Seschrock cb.uic_result = NULL; 2845345Seschrock 2855345Seschrock if (ipmi_user_iter(ihp, ipmi_user_callback, &cb) != 0) 2865345Seschrock return (NULL); 2875345Seschrock 2885345Seschrock if (cb.uic_result == NULL) 2895345Seschrock (void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT, 2905345Seschrock "no such user"); 2915345Seschrock 2925345Seschrock return (cb.uic_result); 2935345Seschrock } 2945345Seschrock 2955345Seschrock int 2965345Seschrock ipmi_user_set_password(ipmi_handle_t *ihp, uint8_t uid, const char *passwd) 2975345Seschrock { 2985345Seschrock ipmi_set_user_password_t req = { 0 }; 2995345Seschrock ipmi_cmd_t cmd; 3005345Seschrock 3015345Seschrock req.isup_uid = uid; 3025345Seschrock req.isup_op = IPMI_PASSWORD_OP_SET; 3035345Seschrock 3045345Seschrock if (strlen(passwd) > 19) 3055345Seschrock return (ipmi_set_error(ihp, EIPMI_INVALID_REQUEST, 3065345Seschrock "password length must be less than 20 characters")); 3075345Seschrock 3085345Seschrock if (strlen(passwd) > 15) 3095345Seschrock req.isup_len20 = 1; 3105345Seschrock 3115345Seschrock (void) strcpy(req.isup_passwd, passwd); 3125345Seschrock 3135345Seschrock cmd.ic_netfn = IPMI_NETFN_APP; 3145345Seschrock cmd.ic_cmd = IPMI_CMD_SET_USER_PASSWORD; 3155345Seschrock cmd.ic_lun = 0; 3165345Seschrock cmd.ic_data = &req; 3175345Seschrock if (req.isup_len20) 3185345Seschrock cmd.ic_dlen = sizeof (req); 3195345Seschrock else 3205345Seschrock cmd.ic_dlen = sizeof (req) - 4; 3215345Seschrock 3225345Seschrock if (ipmi_send(ihp, &cmd) == NULL) 3235345Seschrock return (-1); 3245345Seschrock 3255345Seschrock return (0); 3265345Seschrock } 327