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 /* 225345Seschrock * Copyright 2007 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 335345Seschrock /* 345345Seschrock * Get User Access. See section 22.27. 355345Seschrock * 365345Seschrock * See libipmi.h for a complete description of IPMI reference material. 375345Seschrock */ 385345Seschrock 395345Seschrock typedef struct ipmi_get_user_access_req { 40*5621Seschrock DECL_BITFIELD2( 41*5621Seschrock igua_channel :4, 42*5621Seschrock __reserved1 :4); 43*5621Seschrock DECL_BITFIELD2( 44*5621Seschrock igua_uid :2, 45*5621Seschrock __reserved2 :6); 465345Seschrock } ipmi_get_user_access_req_t; 475345Seschrock 485345Seschrock #define IPMI_CMD_GET_USER_ACCESS 0x44 495345Seschrock 505345Seschrock typedef struct ipmi_get_user_access { 51*5621Seschrock DECL_BITFIELD2( 52*5621Seschrock igua_max_uid :4, 53*5621Seschrock __reserved1 :4); 54*5621Seschrock DECL_BITFIELD2( 55*5621Seschrock igua_enable_status :4, 56*5621Seschrock igua_enabled_uid :4); 57*5621Seschrock DECL_BITFIELD2( 58*5621Seschrock __reserved2 :4, 59*5621Seschrock igua_fixed_uid :4); 60*5621Seschrock DECL_BITFIELD5( 61*5621Seschrock __reserved3 :1, 62*5621Seschrock igua_only_callback :1, 63*5621Seschrock igua_link_auth_enable :1, 64*5621Seschrock igua_ipmi_msg_enable :1, 65*5621Seschrock igua_privilege_level :4); 665345Seschrock } ipmi_get_user_access_t; 675345Seschrock 685345Seschrock #define IPMI_USER_ENABLE_UNSPECIFIED 0x00 695345Seschrock #define IPMI_USER_ENABLE_SETPASSWD 0x01 705345Seschrock #define IPMI_USER_DISABLE_SETPASSWD 0x02 715345Seschrock 725345Seschrock #define IPMI_USER_CHANNEL_CURRENT 0xe 735345Seschrock 745345Seschrock /* 755345Seschrock * Get User Name. See section 22.29 765345Seschrock */ 775345Seschrock 785345Seschrock #define IPMI_CMD_GET_USER_NAME 0x46 795345Seschrock 805345Seschrock /* 815345Seschrock * Set User Password. See section 22.30 825345Seschrock */ 835345Seschrock 845345Seschrock #define IPMI_CMD_SET_USER_PASSWORD 0x47 855345Seschrock 865345Seschrock typedef struct ipmi_set_user_password { 87*5621Seschrock DECL_BITFIELD3( 88*5621Seschrock isup_uid :6, 89*5621Seschrock __reserved1 :1, 90*5621Seschrock isup_len20 :1); 91*5621Seschrock DECL_BITFIELD2( 92*5621Seschrock isup_op :2, 93*5621Seschrock __reserved2 :6); 945345Seschrock char isup_passwd[20]; 955345Seschrock } ipmi_set_user_password_t; 965345Seschrock 975345Seschrock #define IPMI_PASSWORD_OP_DISABLE 0x0 985345Seschrock #define IPMI_PASSWORD_OP_ENABLE 0x1 995345Seschrock #define IPMI_PASSWORD_OP_SET 0x2 1005345Seschrock #define IPMI_PASSWORD_OP_TEST 0x3 1015345Seschrock 1025345Seschrock static ipmi_get_user_access_t * 1035345Seschrock ipmi_get_user_access(ipmi_handle_t *ihp, uint8_t channel, uint8_t uid) 1045345Seschrock { 1055345Seschrock ipmi_cmd_t cmd, *resp; 1065345Seschrock ipmi_get_user_access_req_t req = { 0 }; 1075345Seschrock 1085345Seschrock req.igua_channel = channel; 1095345Seschrock req.igua_uid = uid; 1105345Seschrock 1115345Seschrock cmd.ic_netfn = IPMI_NETFN_APP; 1125345Seschrock cmd.ic_cmd = IPMI_CMD_GET_USER_ACCESS; 1135345Seschrock cmd.ic_lun = 0; 1145345Seschrock cmd.ic_data = &req; 1155345Seschrock cmd.ic_dlen = sizeof (req); 1165345Seschrock 1175345Seschrock if ((resp = ipmi_send(ihp, &cmd)) == NULL) { 1185345Seschrock /* 1195345Seschrock * If sessions aren't supported on the current channel, some 1205345Seschrock * service processors (notably Sun's ILOM) will return an 1215345Seschrock * invalid request completion code (0xCC). For these SPs, we 1225345Seschrock * translate this to the more appropriate EIPMI_INVALID_COMMAND. 1235345Seschrock */ 1245345Seschrock if (ipmi_errno(ihp) == EIPMI_INVALID_REQUEST) 1255345Seschrock (void) ipmi_set_error(ihp, EIPMI_INVALID_COMMAND, 1265345Seschrock NULL); 1275345Seschrock return (NULL); 1285345Seschrock } 1295345Seschrock 1305345Seschrock if (resp->ic_dlen < sizeof (ipmi_get_user_access_t)) { 1315345Seschrock (void) ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL); 1325345Seschrock return (NULL); 1335345Seschrock } 1345345Seschrock 1355345Seschrock return (resp->ic_data); 1365345Seschrock } 1375345Seschrock 1385345Seschrock static const char * 1395345Seschrock ipmi_get_user_name(ipmi_handle_t *ihp, uint8_t uid) 1405345Seschrock { 1415345Seschrock ipmi_cmd_t cmd, *resp; 1425345Seschrock 1435345Seschrock cmd.ic_netfn = IPMI_NETFN_APP; 1445345Seschrock cmd.ic_cmd = IPMI_CMD_GET_USER_ACCESS; 1455345Seschrock cmd.ic_lun = 0; 1465345Seschrock cmd.ic_data = &uid; 1475345Seschrock cmd.ic_dlen = sizeof (uid); 1485345Seschrock 1495345Seschrock if ((resp = ipmi_send(ihp, &cmd)) == NULL) 1505345Seschrock return (NULL); 1515345Seschrock 1525345Seschrock if (resp->ic_dlen < 16) { 1535345Seschrock (void) ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL); 1545345Seschrock return (NULL); 1555345Seschrock } 1565345Seschrock 1575345Seschrock return (resp->ic_data); 1585345Seschrock } 1595345Seschrock 1605345Seschrock void 1615345Seschrock ipmi_user_clear(ipmi_handle_t *ihp) 1625345Seschrock { 1635345Seschrock ipmi_user_t *up, *next; 1645345Seschrock 1655345Seschrock while ((up = ihp->ih_users) != NULL) { 1665345Seschrock next = up->iu_next; 1675345Seschrock ipmi_free(ihp, up->iu_name); 1685345Seschrock ipmi_free(ihp, up); 1695345Seschrock ihp->ih_users = next; 1705345Seschrock } 1715345Seschrock } 1725345Seschrock 1735345Seschrock /* 1745345Seschrock * Returns user information in a well-defined structure. 1755345Seschrock */ 1765345Seschrock int 1775345Seschrock ipmi_user_iter(ipmi_handle_t *ihp, int (*func)(ipmi_user_t *, void *), 1785345Seschrock void *data) 1795345Seschrock { 1805345Seschrock ipmi_get_user_access_t *resp; 1815345Seschrock uint8_t i; 1825345Seschrock ipmi_user_t *up; 1835345Seschrock const char *name; 1845345Seschrock 1855345Seschrock ipmi_user_clear(ihp); 1865345Seschrock 1875345Seschrock /* 1885345Seschrock * First get the number of active users on the system by requesting the 1895345Seschrock * reserved user ID (0). 1905345Seschrock */ 1915345Seschrock if ((resp = ipmi_get_user_access(ihp, 1925345Seschrock IPMI_USER_CHANNEL_CURRENT, 0)) == NULL) 1935345Seschrock return (-1); 1945345Seschrock 1955345Seschrock for (i = 1; i <= resp->igua_max_uid; i++) { 1965345Seschrock if ((resp = ipmi_get_user_access(ihp, 1975345Seschrock IPMI_USER_CHANNEL_CURRENT, i)) == NULL) 1985345Seschrock return (-1); 1995345Seschrock 2005345Seschrock if ((up = ipmi_zalloc(ihp, sizeof (ipmi_user_t))) == NULL) 2015345Seschrock return (-1); 2025345Seschrock 2035345Seschrock up->iu_enabled = resp->igua_enabled_uid; 2045345Seschrock up->iu_uid = i; 2055345Seschrock up->iu_ipmi_msg_enable = resp->igua_ipmi_msg_enable; 2065345Seschrock up->iu_link_auth_enable = resp->igua_link_auth_enable; 2075345Seschrock up->iu_priv = resp->igua_privilege_level; 2085345Seschrock up->iu_next = ihp->ih_users; 2095345Seschrock ihp->ih_users = up; 2105345Seschrock 2115345Seschrock if ((name = ipmi_get_user_name(ihp, i)) == NULL) 2125345Seschrock return (-1); 2135345Seschrock 2145345Seschrock if (*name != '\0' && 2155345Seschrock (up->iu_name = ipmi_strdup(ihp, name)) == NULL) 2165345Seschrock return (-1); 2175345Seschrock } 2185345Seschrock 2195345Seschrock for (up = ihp->ih_users; up != NULL; up = up->iu_next) { 2205345Seschrock if (func(up, data) != 0) 2215345Seschrock return (-1); 2225345Seschrock } 2235345Seschrock 2245345Seschrock return (0); 2255345Seschrock } 2265345Seschrock 2275345Seschrock typedef struct ipmi_user_cb { 2285345Seschrock const char *uic_name; 2295345Seschrock uint8_t uic_uid; 2305345Seschrock ipmi_user_t *uic_result; 2315345Seschrock } ipmi_user_cb_t; 2325345Seschrock 2335345Seschrock static int 2345345Seschrock ipmi_user_callback(ipmi_user_t *up, void *data) 2355345Seschrock { 2365345Seschrock ipmi_user_cb_t *cbp = data; 2375345Seschrock 2385345Seschrock if (cbp->uic_result != NULL) 2395345Seschrock return (0); 2405345Seschrock 2415345Seschrock if (up->iu_name) { 2425345Seschrock if (strcmp(up->iu_name, cbp->uic_name) == 0) 2435345Seschrock cbp->uic_result = up; 2445345Seschrock } else if (up->iu_uid == cbp->uic_uid) { 2455345Seschrock cbp->uic_result = up; 2465345Seschrock } 2475345Seschrock 2485345Seschrock return (0); 2495345Seschrock } 2505345Seschrock 2515345Seschrock ipmi_user_t * 2525345Seschrock ipmi_user_lookup_name(ipmi_handle_t *ihp, const char *name) 2535345Seschrock { 2545345Seschrock ipmi_user_cb_t cb = { 0 }; 2555345Seschrock 2565345Seschrock cb.uic_name = name; 2575345Seschrock cb.uic_result = NULL; 2585345Seschrock 2595345Seschrock if (ipmi_user_iter(ihp, ipmi_user_callback, &cb) != 0) 2605345Seschrock return (NULL); 2615345Seschrock 2625345Seschrock if (cb.uic_result == NULL) 2635345Seschrock (void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT, 2645345Seschrock "no such user"); 2655345Seschrock 2665345Seschrock return (cb.uic_result); 2675345Seschrock } 2685345Seschrock 2695345Seschrock ipmi_user_t * 2705345Seschrock ipmi_user_lookup_id(ipmi_handle_t *ihp, uint8_t uid) 2715345Seschrock { 2725345Seschrock ipmi_user_cb_t cb = { 0 }; 2735345Seschrock 2745345Seschrock cb.uic_uid = uid; 2755345Seschrock cb.uic_result = NULL; 2765345Seschrock 2775345Seschrock if (ipmi_user_iter(ihp, ipmi_user_callback, &cb) != 0) 2785345Seschrock return (NULL); 2795345Seschrock 2805345Seschrock if (cb.uic_result == NULL) 2815345Seschrock (void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT, 2825345Seschrock "no such user"); 2835345Seschrock 2845345Seschrock return (cb.uic_result); 2855345Seschrock } 2865345Seschrock 2875345Seschrock int 2885345Seschrock ipmi_user_set_password(ipmi_handle_t *ihp, uint8_t uid, const char *passwd) 2895345Seschrock { 2905345Seschrock ipmi_set_user_password_t req = { 0 }; 2915345Seschrock ipmi_cmd_t cmd; 2925345Seschrock 2935345Seschrock req.isup_uid = uid; 2945345Seschrock req.isup_op = IPMI_PASSWORD_OP_SET; 2955345Seschrock 2965345Seschrock if (strlen(passwd) > 19) 2975345Seschrock return (ipmi_set_error(ihp, EIPMI_INVALID_REQUEST, 2985345Seschrock "password length must be less than 20 characters")); 2995345Seschrock 3005345Seschrock if (strlen(passwd) > 15) 3015345Seschrock req.isup_len20 = 1; 3025345Seschrock 3035345Seschrock (void) strcpy(req.isup_passwd, passwd); 3045345Seschrock 3055345Seschrock cmd.ic_netfn = IPMI_NETFN_APP; 3065345Seschrock cmd.ic_cmd = IPMI_CMD_SET_USER_PASSWORD; 3075345Seschrock cmd.ic_lun = 0; 3085345Seschrock cmd.ic_data = &req; 3095345Seschrock if (req.isup_len20) 3105345Seschrock cmd.ic_dlen = sizeof (req); 3115345Seschrock else 3125345Seschrock cmd.ic_dlen = sizeof (req) - 4; 3135345Seschrock 3145345Seschrock if (ipmi_send(ihp, &cmd) == NULL) 3155345Seschrock return (-1); 3165345Seschrock 3175345Seschrock return (0); 3185345Seschrock } 319