11af98250Seschrock /* 21af98250Seschrock * CDDL HEADER START 31af98250Seschrock * 41af98250Seschrock * The contents of this file are subject to the terms of the 51af98250Seschrock * Common Development and Distribution License (the "License"). 61af98250Seschrock * You may not use this file except in compliance with the License. 71af98250Seschrock * 81af98250Seschrock * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 91af98250Seschrock * or http://www.opensolaris.org/os/licensing. 101af98250Seschrock * See the License for the specific language governing permissions 111af98250Seschrock * and limitations under the License. 121af98250Seschrock * 131af98250Seschrock * When distributing Covered Code, include this CDDL HEADER in each 141af98250Seschrock * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 151af98250Seschrock * If applicable, add the following below this CDDL HEADER, with the 161af98250Seschrock * fields enclosed by brackets "[]" replaced with your own identifying 171af98250Seschrock * information: Portions Copyright [yyyy] [name of copyright owner] 181af98250Seschrock * 191af98250Seschrock * CDDL HEADER END 201af98250Seschrock */ 211af98250Seschrock /* 22*a1ec709fSEric Schrock * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 231af98250Seschrock * Use is subject to license terms. 241af98250Seschrock */ 251af98250Seschrock 261af98250Seschrock #include <libipmi.h> 271af98250Seschrock #include <string.h> 281af98250Seschrock 291af98250Seschrock #include "ipmi_impl.h" 301af98250Seschrock 312eeaed14Srobj typedef struct ipmi_user_impl { 322eeaed14Srobj ipmi_list_t iu_list; 332eeaed14Srobj ipmi_user_t iu_user; 342eeaed14Srobj } ipmi_user_impl_t; 352eeaed14Srobj 361af98250Seschrock /* 371af98250Seschrock * Get User Access. See section 22.27. 381af98250Seschrock * 391af98250Seschrock * See libipmi.h for a complete description of IPMI reference material. 401af98250Seschrock */ 411af98250Seschrock 421af98250Seschrock typedef struct ipmi_get_user_access_req { 432c32020fSeschrock DECL_BITFIELD2( 442c32020fSeschrock igua_channel :4, 452c32020fSeschrock __reserved1 :4); 462c32020fSeschrock DECL_BITFIELD2( 472c32020fSeschrock igua_uid :2, 482c32020fSeschrock __reserved2 :6); 491af98250Seschrock } ipmi_get_user_access_req_t; 501af98250Seschrock 511af98250Seschrock #define IPMI_CMD_GET_USER_ACCESS 0x44 521af98250Seschrock 531af98250Seschrock typedef struct ipmi_get_user_access { 542c32020fSeschrock DECL_BITFIELD2( 552c32020fSeschrock igua_max_uid :4, 562c32020fSeschrock __reserved1 :4); 572c32020fSeschrock DECL_BITFIELD2( 582c32020fSeschrock igua_enable_status :4, 592c32020fSeschrock igua_enabled_uid :4); 602c32020fSeschrock DECL_BITFIELD2( 612c32020fSeschrock __reserved2 :4, 622c32020fSeschrock igua_fixed_uid :4); 632c32020fSeschrock DECL_BITFIELD5( 642c32020fSeschrock __reserved3 :1, 652c32020fSeschrock igua_only_callback :1, 662c32020fSeschrock igua_link_auth_enable :1, 672c32020fSeschrock igua_ipmi_msg_enable :1, 682c32020fSeschrock igua_privilege_level :4); 691af98250Seschrock } ipmi_get_user_access_t; 701af98250Seschrock 711af98250Seschrock #define IPMI_USER_ENABLE_UNSPECIFIED 0x00 721af98250Seschrock #define IPMI_USER_ENABLE_SETPASSWD 0x01 731af98250Seschrock #define IPMI_USER_DISABLE_SETPASSWD 0x02 741af98250Seschrock 751af98250Seschrock #define IPMI_USER_CHANNEL_CURRENT 0xe 761af98250Seschrock 771af98250Seschrock /* 781af98250Seschrock * Get User Name. See section 22.29 791af98250Seschrock */ 801af98250Seschrock 811af98250Seschrock #define IPMI_CMD_GET_USER_NAME 0x46 821af98250Seschrock 831af98250Seschrock /* 841af98250Seschrock * Set User Password. See section 22.30 851af98250Seschrock */ 861af98250Seschrock 871af98250Seschrock #define IPMI_CMD_SET_USER_PASSWORD 0x47 881af98250Seschrock 891af98250Seschrock typedef struct ipmi_set_user_password { 902c32020fSeschrock DECL_BITFIELD3( 912c32020fSeschrock isup_uid :6, 922c32020fSeschrock __reserved1 :1, 932c32020fSeschrock isup_len20 :1); 942c32020fSeschrock DECL_BITFIELD2( 952c32020fSeschrock isup_op :2, 962c32020fSeschrock __reserved2 :6); 971af98250Seschrock char isup_passwd[20]; 981af98250Seschrock } ipmi_set_user_password_t; 991af98250Seschrock 1001af98250Seschrock #define IPMI_PASSWORD_OP_DISABLE 0x0 1011af98250Seschrock #define IPMI_PASSWORD_OP_ENABLE 0x1 1021af98250Seschrock #define IPMI_PASSWORD_OP_SET 0x2 1031af98250Seschrock #define IPMI_PASSWORD_OP_TEST 0x3 1041af98250Seschrock 1051af98250Seschrock static ipmi_get_user_access_t * 1061af98250Seschrock ipmi_get_user_access(ipmi_handle_t *ihp, uint8_t channel, uint8_t uid) 1071af98250Seschrock { 1081af98250Seschrock ipmi_cmd_t cmd, *resp; 1091af98250Seschrock ipmi_get_user_access_req_t req = { 0 }; 1101af98250Seschrock 1111af98250Seschrock req.igua_channel = channel; 1121af98250Seschrock req.igua_uid = uid; 1131af98250Seschrock 1141af98250Seschrock cmd.ic_netfn = IPMI_NETFN_APP; 1151af98250Seschrock cmd.ic_cmd = IPMI_CMD_GET_USER_ACCESS; 1161af98250Seschrock cmd.ic_lun = 0; 1171af98250Seschrock cmd.ic_data = &req; 1181af98250Seschrock cmd.ic_dlen = sizeof (req); 1191af98250Seschrock 1201af98250Seschrock if ((resp = ipmi_send(ihp, &cmd)) == NULL) { 1211af98250Seschrock /* 1221af98250Seschrock * If sessions aren't supported on the current channel, some 1231af98250Seschrock * service processors (notably Sun's ILOM) will return an 1241af98250Seschrock * invalid request completion code (0xCC). For these SPs, we 1251af98250Seschrock * translate this to the more appropriate EIPMI_INVALID_COMMAND. 1261af98250Seschrock */ 1271af98250Seschrock if (ipmi_errno(ihp) == EIPMI_INVALID_REQUEST) 1281af98250Seschrock (void) ipmi_set_error(ihp, EIPMI_INVALID_COMMAND, 1291af98250Seschrock NULL); 1301af98250Seschrock return (NULL); 1311af98250Seschrock } 1321af98250Seschrock 1331af98250Seschrock if (resp->ic_dlen < sizeof (ipmi_get_user_access_t)) { 1341af98250Seschrock (void) ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL); 1351af98250Seschrock return (NULL); 1361af98250Seschrock } 1371af98250Seschrock 1381af98250Seschrock return (resp->ic_data); 1391af98250Seschrock } 1401af98250Seschrock 1411af98250Seschrock static const char * 1421af98250Seschrock ipmi_get_user_name(ipmi_handle_t *ihp, uint8_t uid) 1431af98250Seschrock { 1441af98250Seschrock ipmi_cmd_t cmd, *resp; 1451af98250Seschrock 1461af98250Seschrock cmd.ic_netfn = IPMI_NETFN_APP; 147*a1ec709fSEric Schrock cmd.ic_cmd = IPMI_CMD_GET_USER_NAME; 1481af98250Seschrock cmd.ic_lun = 0; 1491af98250Seschrock cmd.ic_data = &uid; 1501af98250Seschrock cmd.ic_dlen = sizeof (uid); 1511af98250Seschrock 1521af98250Seschrock if ((resp = ipmi_send(ihp, &cmd)) == NULL) 1531af98250Seschrock return (NULL); 1541af98250Seschrock 1551af98250Seschrock if (resp->ic_dlen < 16) { 1561af98250Seschrock (void) ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL); 1571af98250Seschrock return (NULL); 1581af98250Seschrock } 1591af98250Seschrock 1601af98250Seschrock return (resp->ic_data); 1611af98250Seschrock } 1621af98250Seschrock 1631af98250Seschrock void 1641af98250Seschrock ipmi_user_clear(ipmi_handle_t *ihp) 1651af98250Seschrock { 1662eeaed14Srobj ipmi_user_impl_t *uip; 1671af98250Seschrock 1682eeaed14Srobj while ((uip = ipmi_list_next(&ihp->ih_users)) != NULL) { 1692eeaed14Srobj ipmi_list_delete(&ihp->ih_users, uip); 1702eeaed14Srobj ipmi_free(ihp, uip->iu_user.iu_name); 1712eeaed14Srobj ipmi_free(ihp, uip); 1721af98250Seschrock } 1731af98250Seschrock } 1741af98250Seschrock 1751af98250Seschrock /* 1761af98250Seschrock * Returns user information in a well-defined structure. 1771af98250Seschrock */ 1781af98250Seschrock int 1791af98250Seschrock ipmi_user_iter(ipmi_handle_t *ihp, int (*func)(ipmi_user_t *, void *), 1801af98250Seschrock void *data) 1811af98250Seschrock { 1821af98250Seschrock ipmi_get_user_access_t *resp; 183*a1ec709fSEric Schrock uint8_t i, uid_max; 1842eeaed14Srobj ipmi_user_impl_t *uip; 1851af98250Seschrock ipmi_user_t *up; 1861af98250Seschrock const char *name; 187*a1ec709fSEric Schrock uint8_t channel; 188*a1ec709fSEric Schrock ipmi_deviceid_t *devid; 1891af98250Seschrock 1901af98250Seschrock ipmi_user_clear(ihp); 1911af98250Seschrock 192*a1ec709fSEric Schrock channel = IPMI_USER_CHANNEL_CURRENT; 193*a1ec709fSEric Schrock 1941af98250Seschrock /* 195*a1ec709fSEric Schrock * Get the number of active users on the system by requesting the first 196*a1ec709fSEric Schrock * user ID (1). 1971af98250Seschrock */ 198*a1ec709fSEric Schrock if ((resp = ipmi_get_user_access(ihp, channel, 1)) == NULL) { 199*a1ec709fSEric Schrock /* 200*a1ec709fSEric Schrock * Some versions of the Sun ILOM have a bug which prevent the 201*a1ec709fSEric Schrock * GET USER ACCESS command from succeeding over the default 202*a1ec709fSEric Schrock * channel. If this fails and we are on ILOM, then attempt to 203*a1ec709fSEric Schrock * use the standard channel (1) instead. 204*a1ec709fSEric Schrock */ 205*a1ec709fSEric Schrock if ((devid = ipmi_get_deviceid(ihp)) == NULL) 2061af98250Seschrock return (-1); 2071af98250Seschrock 208*a1ec709fSEric Schrock if (!ipmi_is_sun_ilom(devid)) 209*a1ec709fSEric Schrock return (-1); 210*a1ec709fSEric Schrock 211*a1ec709fSEric Schrock channel = 1; 212*a1ec709fSEric Schrock if ((resp = ipmi_get_user_access(ihp, channel, 1)) == NULL) 213*a1ec709fSEric Schrock return (-1); 214*a1ec709fSEric Schrock } 215*a1ec709fSEric Schrock 216*a1ec709fSEric Schrock uid_max = resp->igua_max_uid; 217*a1ec709fSEric Schrock for (i = 1; i <= uid_max; i++) { 218*a1ec709fSEric Schrock if (i != 1 && (resp = ipmi_get_user_access(ihp, 219*a1ec709fSEric Schrock channel, i)) == NULL) 2201af98250Seschrock return (-1); 2211af98250Seschrock 2222eeaed14Srobj if ((uip = ipmi_zalloc(ihp, sizeof (ipmi_user_impl_t))) == NULL) 2231af98250Seschrock return (-1); 2241af98250Seschrock 2252eeaed14Srobj up = &uip->iu_user; 2262eeaed14Srobj 2271af98250Seschrock up->iu_enabled = resp->igua_enabled_uid; 2281af98250Seschrock up->iu_uid = i; 2291af98250Seschrock up->iu_ipmi_msg_enable = resp->igua_ipmi_msg_enable; 2301af98250Seschrock up->iu_link_auth_enable = resp->igua_link_auth_enable; 2311af98250Seschrock up->iu_priv = resp->igua_privilege_level; 2322eeaed14Srobj 2332eeaed14Srobj ipmi_list_append(&ihp->ih_users, uip); 2341af98250Seschrock 235*a1ec709fSEric Schrock /* 236*a1ec709fSEric Schrock * If we are requesting a username that doesn't have a 237*a1ec709fSEric Schrock * supported username, we may get an INVALID REQUEST response. 238*a1ec709fSEric Schrock * If this is the case, then continue as if there is no known 239*a1ec709fSEric Schrock * username. 240*a1ec709fSEric Schrock */ 241*a1ec709fSEric Schrock if ((name = ipmi_get_user_name(ihp, i)) == NULL) { 242*a1ec709fSEric Schrock if (ipmi_errno(ihp) == EIPMI_INVALID_REQUEST) 243*a1ec709fSEric Schrock continue; 244*a1ec709fSEric Schrock else 2451af98250Seschrock return (-1); 246*a1ec709fSEric Schrock } 2471af98250Seschrock 248*a1ec709fSEric Schrock if (*name == '\0') 249*a1ec709fSEric Schrock continue; 250*a1ec709fSEric Schrock 251*a1ec709fSEric Schrock if ((up->iu_name = ipmi_strdup(ihp, name)) == NULL) 2521af98250Seschrock return (-1); 2531af98250Seschrock } 2541af98250Seschrock 2552eeaed14Srobj for (uip = ipmi_list_next(&ihp->ih_users); uip != NULL; 2562eeaed14Srobj uip = ipmi_list_next(uip)) { 2572eeaed14Srobj if (func(&uip->iu_user, data) != 0) 2581af98250Seschrock return (-1); 2591af98250Seschrock } 2601af98250Seschrock 2611af98250Seschrock return (0); 2621af98250Seschrock } 2631af98250Seschrock 2641af98250Seschrock typedef struct ipmi_user_cb { 2651af98250Seschrock const char *uic_name; 2661af98250Seschrock uint8_t uic_uid; 2671af98250Seschrock ipmi_user_t *uic_result; 2681af98250Seschrock } ipmi_user_cb_t; 2691af98250Seschrock 2701af98250Seschrock static int 2711af98250Seschrock ipmi_user_callback(ipmi_user_t *up, void *data) 2721af98250Seschrock { 2731af98250Seschrock ipmi_user_cb_t *cbp = data; 2741af98250Seschrock 2751af98250Seschrock if (cbp->uic_result != NULL) 2761af98250Seschrock return (0); 2771af98250Seschrock 2781af98250Seschrock if (up->iu_name) { 2791af98250Seschrock if (strcmp(up->iu_name, cbp->uic_name) == 0) 2801af98250Seschrock cbp->uic_result = up; 2811af98250Seschrock } else if (up->iu_uid == cbp->uic_uid) { 2821af98250Seschrock cbp->uic_result = up; 2831af98250Seschrock } 2841af98250Seschrock 2851af98250Seschrock return (0); 2861af98250Seschrock } 2871af98250Seschrock 2881af98250Seschrock ipmi_user_t * 2891af98250Seschrock ipmi_user_lookup_name(ipmi_handle_t *ihp, const char *name) 2901af98250Seschrock { 2911af98250Seschrock ipmi_user_cb_t cb = { 0 }; 2921af98250Seschrock 2931af98250Seschrock cb.uic_name = name; 2941af98250Seschrock cb.uic_result = NULL; 2951af98250Seschrock 2961af98250Seschrock if (ipmi_user_iter(ihp, ipmi_user_callback, &cb) != 0) 2971af98250Seschrock return (NULL); 2981af98250Seschrock 2991af98250Seschrock if (cb.uic_result == NULL) 3001af98250Seschrock (void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT, 3011af98250Seschrock "no such user"); 3021af98250Seschrock 3031af98250Seschrock return (cb.uic_result); 3041af98250Seschrock } 3051af98250Seschrock 3061af98250Seschrock ipmi_user_t * 3071af98250Seschrock ipmi_user_lookup_id(ipmi_handle_t *ihp, uint8_t uid) 3081af98250Seschrock { 3091af98250Seschrock ipmi_user_cb_t cb = { 0 }; 3101af98250Seschrock 3111af98250Seschrock cb.uic_uid = uid; 3121af98250Seschrock cb.uic_result = NULL; 3131af98250Seschrock 3141af98250Seschrock if (ipmi_user_iter(ihp, ipmi_user_callback, &cb) != 0) 3151af98250Seschrock return (NULL); 3161af98250Seschrock 3171af98250Seschrock if (cb.uic_result == NULL) 3181af98250Seschrock (void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT, 3191af98250Seschrock "no such user"); 3201af98250Seschrock 3211af98250Seschrock return (cb.uic_result); 3221af98250Seschrock } 3231af98250Seschrock 3241af98250Seschrock int 3251af98250Seschrock ipmi_user_set_password(ipmi_handle_t *ihp, uint8_t uid, const char *passwd) 3261af98250Seschrock { 3271af98250Seschrock ipmi_set_user_password_t req = { 0 }; 3281af98250Seschrock ipmi_cmd_t cmd; 3291af98250Seschrock 3301af98250Seschrock req.isup_uid = uid; 3311af98250Seschrock req.isup_op = IPMI_PASSWORD_OP_SET; 3321af98250Seschrock 3331af98250Seschrock if (strlen(passwd) > 19) 3341af98250Seschrock return (ipmi_set_error(ihp, EIPMI_INVALID_REQUEST, 3351af98250Seschrock "password length must be less than 20 characters")); 3361af98250Seschrock 3371af98250Seschrock if (strlen(passwd) > 15) 3381af98250Seschrock req.isup_len20 = 1; 3391af98250Seschrock 3401af98250Seschrock (void) strcpy(req.isup_passwd, passwd); 3411af98250Seschrock 3421af98250Seschrock cmd.ic_netfn = IPMI_NETFN_APP; 3431af98250Seschrock cmd.ic_cmd = IPMI_CMD_SET_USER_PASSWORD; 3441af98250Seschrock cmd.ic_lun = 0; 3451af98250Seschrock cmd.ic_data = &req; 3461af98250Seschrock if (req.isup_len20) 3471af98250Seschrock cmd.ic_dlen = sizeof (req); 3481af98250Seschrock else 3491af98250Seschrock cmd.ic_dlen = sizeof (req) - 4; 3501af98250Seschrock 3511af98250Seschrock if (ipmi_send(ihp, &cmd) == NULL) 3521af98250Seschrock return (-1); 3531af98250Seschrock 3541af98250Seschrock return (0); 3551af98250Seschrock } 356